Ticket #5538: family_improve-fh-5538-submitted.patch

File family_improve-fh-5538-submitted.patch, 48.1 KB (added by hivert, 13 years ago)
  • sage/combinat/all.py

    # HG changeset patch
    # User Florent Hivert <Florent.Hivert@univ-rouen.fr>
    # Date 1239055424 -7200
    # Node ID 9b6a8f3a5815989164fbc9c65292b0758738e373
    # Parent  9238d062dad746e6bb6b4de5846b39415f3a4545
    Improved family:
     - now handle list and tuple with TrivialFamily; 
     - copy the input to avoid modification;
     - correct pickling of function and attrcall; 
     - moved to sage.set
    
    diff -r 9238d062dad7 -r 9b6a8f3a5815 sage/combinat/all.py
    a b  
    9898
    9999from multichoose_nk import MultichooseNK
    100100
    101 from family import Family, FiniteFamily, LazyFamily
  • sage/combinat/family.py

    diff -r 9238d062dad7 -r 9b6a8f3a5815 sage/combinat/family.py
    a b  
    1 """
    2 Families
    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 #*****************************************************************************
    19 from sage.combinat.combinat import CombinatorialClass
    20 from sage.combinat.finite_class import FiniteCombinatorialClass_l
    21 from sage.rings.all import ZZ
    22 
    23 def Family(indices, function = None, name = None, hidden_keys = [], hidden_function = None):
    24     r"""
    25     A Family is an associative container which models a family
    26     `(f_i)_{i \in I}`. Then, f[i] returns the element of the family
    27     indexed by i. Whenever available, set and combinatorial class
    28     operations (counting, iteration, listing) on the family are induced
    29     from those of the index set.
    30    
    31     There are several available implementations (classes) for different
    32     usages; Family serves as a factory, and will create instances of
    33     the appropriate classes depending on its arguments.
    34    
    35     EXAMPLES:
    36    
    37     In its simplest form, a list l by itself is considered as the
    38     family `(l[i]_{i \in I})` where `I` is the range
    39     `0\dots,len(l)`. So Family(l) just returns it.
    40    
    41     ::
    42    
    43         sage: f = Family([1,2,3])
    44         sage: f
    45         [1, 2, 3]
    46    
    47     A family can also be constructed from a dictionary t. The resulting
    48     family is very close to t, except that the elements of the family
    49     are the values of t. Here, we define the family `(f_i)_{i \in \{3,4,7\}}`
    50     with f_3='a', f_4='b', and f_7='d'::
    51    
    52         sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
    53         sage: f
    54         Finite family {3: 'a', 4: 'b', 7: 'd'}
    55         sage: f[7]
    56         'd'
    57         sage: len(f)
    58         3
    59         sage: list(f)
    60         ['a', 'b', 'd']
    61         sage: [ x for x in f ]
    62         ['a', 'b', 'd']
    63         sage: f.keys()
    64         [3, 4, 7]
    65         sage: 'b' in f 
    66         True
    67         sage: 'e' in f
    68         False
    69    
    70     A family can also be constructed by its index set `I` and
    71     a function `f`, as in `(f(i))_{i \in I}`::
    72    
    73         sage: f = Family([3,4,7], lambda i: 2*i)
    74         sage: f
    75         Finite family {3: 6, 4: 8, 7: 14}
    76         sage: f.keys()
    77         [3, 4, 7]
    78         sage: f[7]
    79         14
    80         sage: list(f)
    81         [6, 8, 14]
    82         sage: [x for x in f]
    83         [6, 8, 14]
    84         sage: len(f)
    85         3
    86    
    87     By default, if the index set is a list, all images are computed
    88     right away, and stored in an internal dictionary. Note that this
    89     requires all the elements of the list to be hashable. One can ask
    90     instead for the images `f(i)` to be computed lazily, when
    91     needed::
    92    
    93         sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
    94         sage: f
    95         Lazy family (f(i))_{i in [3, 4, 7]}
    96         sage: f[7]
    97         14
    98         sage: list(f)
    99         [6, 8, 14]
    100         sage: [x for x in f]
    101         [6, 8, 14]
    102    
    103     This allows in particular for modeling infinite families::
    104    
    105         sage: f = Family(ZZ, lambda i: 2r*i)
    106         sage: f
    107         Lazy family (f(i))_{i in Integer Ring}
    108         sage: f.keys()
    109         Integer Ring
    110         sage: f[1]
    111         2
    112         sage: f[-5]
    113         -10
    114         sage: i = iter(f)
    115         sage: i.next(), i.next(), i.next(), i.next(), i.next()
    116         (0, 2, -2, 4, -4)
    117    
    118     Beware that for those kind of families len(f) is not supposed to
    119     work. As a replacement, use the .cardinality() method::
    120    
    121        sage: f = LazyFamily(Permutations(3), lambda i: (i.to_lehmer_code()))
    122        sage: list(f)
    123        [[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0], [2, 0, 0], [2, 1, 0]]
    124        sage: f.cardinality()
    125        6
    126 
    127     Caveat: Only certain families with lazy behavior can be pickled. In
    128     particular, only functions that work with Sage's pickle_function
    129     and unpickle_function (in sage.misc.fpickle) will correctly
    130     unpickle.
    131    
    132     Finally, it can occasionally be useful to add some hidden elements
    133     in a family, which are accessible as f[i], but do not appear in the
    134     keys or the container operations.
    135    
    136     ::
    137    
    138         sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
    139         sage: f
    140         Finite family {3: 6, 4: 8, 7: 14}
    141         sage: f.keys()
    142         [3, 4, 7]
    143         sage: f.hidden_keys()
    144         [2]
    145         sage: f[7]
    146         14
    147         sage: f[2]
    148         4
    149         sage: list(f)
    150         [6, 8, 14]
    151         sage: [x for x in f]
    152         [6, 8, 14]
    153         sage: len(f)
    154         3
    155    
    156     The following example illustrates when the function is actually
    157     called::
    158    
    159         sage: def compute_value(i):
    160         ...       print('computing 2*'+str(i))
    161         ...       return 2*i
    162         sage: f = Family([3,4,7], compute_value, hidden_keys=[2])
    163         computing 2*3
    164         computing 2*4
    165         computing 2*7
    166         sage: f
    167         Finite family {3: 6, 4: 8, 7: 14}
    168         sage: f.keys()
    169         [3, 4, 7]
    170         sage: f.hidden_keys()
    171         [2]
    172         sage: f[7]
    173         14
    174         sage: f[2]
    175         computing 2*2
    176         4
    177         sage: f[2]
    178         4
    179         sage: list(f)
    180         [6, 8, 14]
    181         sage: [x for x in f]
    182         [6, 8, 14]
    183         sage: len(f)
    184         3
    185    
    186     Here is a close variant where the function for the hidden keys is
    187     different from that for the other keys::
    188    
    189         sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2], hidden_function = lambda i: 3*i)
    190         sage: f
    191         Finite family {3: 6, 4: 8, 7: 14}
    192         sage: f.keys()
    193         [3, 4, 7]
    194         sage: f.hidden_keys()
    195         [2]
    196         sage: f[7]
    197         14
    198         sage: f[2]
    199         6
    200         sage: list(f)
    201         [6, 8, 14]
    202         sage: [x for x in f]
    203         [6, 8, 14]
    204         sage: len(f)
    205         3
    206    
    207     Family behaves the same way with FiniteCombinatorialClass instances
    208     and lists. This feature will eventually disappear when
    209     FiniteCombinatorialClass won't be needed anymore.
    210    
    211     ::
    212    
    213         sage: f = Family(FiniteCombinatorialClass([1,2,3]))
    214         sage: f
    215         Combinatorial class with elements in [1, 2, 3]
    216    
    217     ::
    218    
    219         sage: f = Family(FiniteCombinatorialClass([3,4,7]), lambda i: 2*i)
    220         sage: f
    221         Finite family {3: 6, 4: 8, 7: 14}
    222         sage: f.keys()
    223         [3, 4, 7]
    224         sage: f[7]
    225         14
    226         sage: list(f)
    227         [6, 8, 14]
    228         sage: [x for x in f]
    229         [6, 8, 14]
    230         sage: len(f)
    231         3
    232    
    233     TESTS::
    234    
    235         sage: f = Family({1:'a', 2:'b', 3:'c'})
    236         sage: f
    237         Finite family {1: 'a', 2: 'b', 3: 'c'}
    238         sage: f[2]
    239         'b'
    240         sage: loads(dumps(f)) == f
    241         True
    242    
    243     ::
    244    
    245         sage: f = Family(range(1,27), lambda i: chr(i+96))
    246         sage: f
    247             Finite family {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z'}
    248         sage: f[2]
    249         'b'
    250     """
    251     assert(type(hidden_keys) == list)
    252     if function == None and hidden_keys == []:
    253         if type(indices) == list or isinstance(indices, FiniteCombinatorialClass_l) or isinstance(indices, FiniteFamily) or isinstance(indices, LazyFamily):
    254             return indices
    255         if type(indices) == dict:
    256             return FiniteFamily(indices)
    257     else:
    258         if type(indices) == list or isinstance(indices, FiniteCombinatorialClass_l):
    259             if not hidden_keys == []:
    260                 if hidden_function is None:
    261                     hidden_function = function
    262                 return FiniteFamilyWithHiddenKeys(dict([(i, function(i)) for i in indices]),
    263                                                   hidden_keys, hidden_function)
    264             else:
    265                 return FiniteFamily(dict([(i, function(i)) for i in indices]), keys = indices)
    266         elif hidden_keys == [] and hidden_function is None:
    267             return LazyFamily(indices, function)
    268     raise NotImplementedError
    269 
    270 class AbstractFamily(CombinatorialClass):
    271     def hidden_keys(self):
    272         """
    273         Returns the hidden keys of the family, if any.
    274        
    275         EXAMPLES::
    276        
    277             sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
    278             sage: f.hidden_keys()
    279             []
    280         """
    281         return []
    282 
    283     def zip(self, f, other, name = None):
    284         """
    285         Given two families with same index set `I` (and same hidden
    286         keys if relevant), returns the family
    287         `( f(self[i], other[i]) )_{i \in I}`
    288        
    289         TODO: generalize to any number of families and merge with map?
    290        
    291         EXAMPLES::
    292        
    293             sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
    294             sage: g = Family({3: '1', 4: '2', 7: '3'})
    295             sage: h = f.zip(lambda x,y: x+y, g)
    296             sage: list(h)
    297             ['a1', 'b2', 'd3']
    298         """
    299         assert(self.keys() == other.keys())
    300         assert(self.hidden_keys() == other.hidden_keys())
    301         return Family(self.keys(), lambda i: f(self[i],other[i]), hidden_keys = self.hidden_keys(), name = name)
    302 
    303     def map(self, f, name = None):
    304         """
    305         Returns the family `( f(\mathtt{self}[i]) )_{i \in I}`, where
    306         `I` is the index set of self.
    307        
    308         TODO: good name?
    309        
    310         EXAMPLES::
    311        
    312             sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
    313             sage: g = f.map(lambda x: x+'1')
    314             sage: list(g)
    315             ['a1', 'b1', 'd1']
    316         """
    317         return Family(self.keys(), lambda i: f(self[i]), hidden_keys = self.hidden_keys(), name = name)
    318 
    319 class FiniteFamily(AbstractFamily):
    320     r"""
    321     A FiniteFamily is an associative container which models a finite
    322     family `(f_i)_{i \in I}`. Its elements `f_i` are therefore
    323     its values. Instances should be created via the Family factory,
    324     which see for further examples and tests.
    325    
    326     EXAMPLES: We define the family `(f_i)_{i \in \{3,4,7\}}` with f_3=a,
    327     f_4=b, and f_7=d
    328    
    329     ::
    330    
    331         sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
    332    
    333     Individual elements are accessible as in a usual dictionary::
    334    
    335         sage: f[7]
    336         'd'
    337    
    338     And the other usual dictionary operations are also available::
    339    
    340         sage: len(f)
    341         3
    342         sage: f.keys()
    343         [3, 4, 7]
    344    
    345     However f behaves as a container for the `f_i`'s::
    346    
    347         sage: list(f)
    348         ['a', 'b', 'd']
    349         sage: [ x for x in f ]
    350         ['a', 'b', 'd']
    351     """
    352 
    353     def __init__(self, dictionary, keys = None):
    354         """
    355         TESTS::
    356        
    357             sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
    358             sage: f == loads(dumps(f))
    359             True
    360         """
    361         # TODO: use keys to specify the order of the elements
    362         self.dictionary = dictionary
    363         self.keys = dictionary.keys
    364         self.values = dictionary.values
    365 
    366     def __repr__(self):
    367         """
    368         EXAMPLES::
    369        
    370             sage: FiniteFamily({3: 'a'})
    371             Finite family {3: 'a'}
    372         """
    373         return "Finite family %s"%self.dictionary
    374 
    375     def __contains__(self, x):
    376         """
    377         EXAMPLES::
    378        
    379             sage: f = FiniteFamily({3: 'a'})
    380             sage: 'a' in f
    381             True
    382             sage: 'b' in f
    383             False
    384         """
    385         return x in self.values()
    386 
    387     def __len__(self):
    388         """
    389         Returns the number of elements in self.
    390 
    391         EXAMPLES::
    392        
    393             sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
    394             sage: len(f)
    395             3       
    396         """
    397         return len(self.dictionary)
    398    
    399     def cardinality(self):
    400         """
    401         Returns the number of elements in self.
    402        
    403         EXAMPLES::
    404        
    405             sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
    406             sage: f.cardinality()
    407             3
    408         """
    409         return ZZ(len(self.dictionary))
    410 
    411     def __iter__(self):
    412         """
    413         EXAMPLES::
    414        
    415             sage: f = FiniteFamily({3: 'a'})
    416             sage: i = iter(f)
    417             sage: i.next()
    418             'a'
    419         """
    420         return iter(self.values())
    421 
    422     def __getitem__(self, i):
    423         """
    424         Note that we can't just do self.__getitem__ =
    425         dictionary.__getitem__ in the __init__ method since Python
    426         queries the object's type/class for the special methods rather than
    427         querying the object itself.
    428        
    429         EXAMPLES::
    430        
    431             sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
    432             sage: f[3]
    433             'a'
    434         """
    435         return self.dictionary.__getitem__(i)
    436 
    437     # For the pickle and copy modules
    438     def __getstate__(self):
    439         """
    440         TESTS::
    441        
    442             sage: f = FiniteFamily({3: 'a'})
    443             sage: f.__getstate__()
    444             {'dictionary': {3: 'a'}}
    445         """
    446         return {'dictionary': self.dictionary}
    447 
    448     def __setstate__(self, state):
    449         """
    450         EXAMPLES::
    451        
    452             sage: f = FiniteFamily({3: 'a'})
    453             sage: f.__setstate__({'dictionary': {4:'b'}})
    454             sage: f
    455             Finite family {4: 'b'}
    456         """
    457         self.__init__(state['dictionary'])
    458 
    459 class FiniteFamilyWithHiddenKeys(FiniteFamily):
    460     r"""
    461     A close variant of FiniteFamily where the family contains some
    462     hidden keys whose corresponding values are computed lazily (and
    463     remembered). Instances should be created via the Family factory,
    464     which see for examples and tests.
    465    
    466     Caveat: Only instances of this class whose functions are compatible
    467     with sage.misc.fpickle can be pickled.
    468     """
    469     def __init__(self, dictionary, hidden_keys, hidden_function):
    470         """
    471         EXAMPLES::
    472        
    473             sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2])
    474             sage: f == loads(dumps(f))
    475             True
    476         """
    477         FiniteFamily.__init__(self, dictionary)
    478         self._hidden_keys = hidden_keys
    479         self.hidden_function = hidden_function
    480         self.hidden_dictionary = {}
    481 
    482         # would be better to define as usual method
    483         # any better to unset the def of __getitem__ by FiniteFamily?
    484         #self.__getitem__ = lambda i: dictionary[i] if dictionary.has_key(i) else hidden_dictionary[i]
    485 
    486     def __getitem__(self, i):
    487         """
    488         EXAMPLES::
    489        
    490             sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
    491             sage: f[3]
    492             6
    493             sage: f[2]
    494             4
    495             sage: f[5]
    496             Traceback (most recent call last):
    497             ...
    498             KeyError
    499         """
    500         if i in self.dictionary:
    501             return self.dictionary[i]
    502 
    503         if i not in self.hidden_dictionary:
    504             if i not in self._hidden_keys:
    505                 raise KeyError
    506             self.hidden_dictionary[i] = self.hidden_function(i)
    507 
    508         return self.hidden_dictionary[i]
    509 
    510     def hidden_keys(self):
    511         """
    512         Returns self's hidden keys.
    513        
    514         EXAMPLES::
    515        
    516             sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
    517             sage: f.hidden_keys()
    518             [2]
    519         """
    520         return self._hidden_keys
    521 
    522     def __getstate__(self):
    523         """
    524         EXAMPLES::
    525        
    526             sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
    527             sage: d = f.__getstate__()
    528             sage: d['hidden_keys']
    529             [2]
    530         """
    531         from sage.misc.fpickle import pickle_function
    532         f = pickle_function(self.hidden_function)
    533         return {'dictionary': self.dictionary,
    534                 'hidden_keys': self._hidden_keys,
    535                 'hidden_dictionary': self.hidden_dictionary,
    536                 'hidden_function': f}
    537 
    538     def __setstate__(self, d):
    539         """
    540         EXAMPLES::
    541        
    542             sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2])
    543             sage: d = f.__getstate__()
    544             sage: f = Family([4,5,6], lambda i: 2r*i, hidden_keys=[2])
    545             sage: f.__setstate__(d)
    546             sage: f.keys()
    547             [3, 4, 7]
    548             sage: f[3]
    549             6
    550         """
    551         from sage.misc.fpickle import unpickle_function
    552         hidden_function = unpickle_function(d['hidden_function'])
    553         self.__init__(d['dictionary'], d['hidden_keys'], hidden_function)
    554         self.hidden_dictionary = d['hidden_dictionary']
    555 
    556 
    557 class LazyFamily(AbstractFamily):
    558     r"""
    559     A LazyFamily(I, f) is an associative container which models the
    560     (possibly infinite) family `(f(i))_{i \in I}`.
    561    
    562     Instances should be created via the Family factory, which see for
    563     examples and tests.
    564     """
    565     def __init__(self, set, function, name = "f"):
    566         """
    567         EXAMPLES::
    568        
    569             sage: f = LazyFamily([3,4,7], lambda i: 2r*i); f
    570             Lazy family (f(i))_{i in [3, 4, 7]}
    571             sage: f == loads(dumps(f))
    572             True
    573         """
    574         self.set = set
    575         self.name = name
    576         self.function = function
    577 
    578     def __repr__(self):
    579         """
    580         EXAMPLES::
    581        
    582             sage: f = LazyFamily([3,4,7], lambda i: 2*i); f
    583             Lazy family (f(i))_{i in [3, 4, 7]}
    584         """
    585         return "Lazy family (%s(i))_{i in %s}"%(self.name,self.set)
    586 
    587     def keys(self):
    588         """
    589         Returns self's keys.
    590        
    591         EXAMPLES::
    592        
    593             sage: f = LazyFamily([3,4,7], lambda i: 2*i)
    594             sage: f.keys()
    595             [3, 4, 7]
    596         """
    597         return self.set
    598 
    599     def cardinality(self):
    600         """
    601         Return the number of elements in self.
    602        
    603         EXAMPLES::
    604        
    605             sage: f = LazyFamily([3,4,7], lambda i: 2*i)
    606             sage: f.cardinality()
    607             3
    608         """
    609         try:
    610             return ZZ(len(self.set))
    611         except AttributeError:
    612             return self.set.cardinality()
    613    
    614     def __iter__(self):
    615         """
    616         EXAMPLES::
    617        
    618             sage: f = LazyFamily([3,4,7], lambda i: 2*i)
    619             sage: [i for i in f]
    620             [6, 8, 14]
    621         """
    622         for i in self.set:
    623             yield self[i]
    624 
    625     def __getitem__(self, i):
    626         """       
    627         EXAMPLES::
    628        
    629             sage: f = LazyFamily([3,4,7], lambda i: 2*i)
    630             sage: f[3]
    631             6
    632        
    633         TESTS::
    634        
    635             sage: f[5]
    636             10
    637         """
    638         return self.function(i)
    639 
    640     def __getstate__(self):
    641         """       
    642         EXAMPLES::
    643        
    644             sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
    645             sage: d = f.__getstate__()
    646             sage: d['set']
    647             [3, 4, 7]
    648         """
    649         from sage.misc.fpickle import pickle_function
    650         f = pickle_function(self.function)
    651         return {'set': self.set,
    652                 'name': self.name,
    653                 'function': f}
    654 
    655     def __setstate__(self, d):
    656         """
    657         EXAMPLES::
    658        
    659             sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
    660             sage: d = f.__getstate__()
    661             sage: f = LazyFamily([4,5,6], lambda i: 2r*i)
    662             sage: f.__setstate__(d)
    663             sage: f.keys()
    664             [3, 4, 7]
    665             sage: f[3]
    666             6
    667         """
    668         from sage.misc.fpickle import unpickle_function
    669         function = unpickle_function(d['function'])
    670         self.__init__(d['set'], function, d['name'])
     1# Backward compatibility pointer
     2from sage.sets.family import Family
  • sage/combinat/finite_class.py

    diff -r 9238d062dad7 -r 9b6a8f3a5815 sage/combinat/finite_class.py
    a b  
    1717#*****************************************************************************
    1818from combinat import CombinatorialClass
    1919
    20 def FiniteCombinatorialClass(l):
     20class FiniteCombinatorialClass(CombinatorialClass):
    2121    """
    22     Returns the combinatorial class with elements in l.
     22    INPUT:
     23     - l a list or iterable
     24   
     25    Returns l, wrapped as a combinatorial class
    2326   
    2427    EXAMPLES::
    2528   
     
    3538        sage: F.last()
    3639        3
    3740    """
    38     if not isinstance(l, list):
    39         l = list(l)
    40     return FiniteCombinatorialClass_l(l)
    41    
    42 class FiniteCombinatorialClass_l(CombinatorialClass):
    4341    def __init__(self, l):
    4442        """
    4543        TESTS::
     
    4846            sage: F == loads(dumps(F))
    4947            True
    5048        """
    51         self.l = l
     49        self.l = list(l) # Probably would be better to use a tuple
    5250
    5351    def object_class(self, x):
    5452        """
     
    7270
    7371    def __contains__(self, x):
    7472        """
    75         TESTS::
     73        EXAMPLES::
    7674       
    7775            sage: F = FiniteCombinatorialClass([1,2,3])
    7876            sage: 1 in F
     
    9896
    9997    def cardinality(self):
    10098        """
    101         TESTS::
     99        EXAMPLES::
    102100       
    103101            sage: F = FiniteCombinatorialClass([1,2,3])
    104102            sage: F.cardinality()
     
    106104        """       
    107105        return len(self.l)
    108106
     107
     108    def __getitem__(self, i): # TODO: optimize
     109        """
     110        EXAMPLES::
     111       
     112            sage: F = FiniteCombinatorialClass(["a", "b", "c"])
     113            sage: F[2]
     114            'c'
     115        """       
     116        return self.l[i]
     117
     118    def keys(self):
     119        """
     120        EXAMPLES:
     121            sage: F = FiniteCombinatorialClass([1,2,3])
     122            sage: F.keys()
     123            [0, 1, 2]
     124        """
     125        return range(len(self.l))
  • sage/sets/all.py

    diff -r 9238d062dad7 -r 9b6a8f3a5815 sage/sets/all.py
    a b  
    11from set import Set, is_Set, EnumeratedSet
    22
    33from primes import Primes
     4
     5from family import Family, FiniteFamily, LazyFamily, TrivialFamily
  • new file sage/sets/family.py

    diff -r 9238d062dad7 -r 9b6a8f3a5815 sage/sets/family.py
    - +  
     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#*****************************************************************************
     19from sage.combinat.combinat import CombinatorialClass
     20from sage.combinat.finite_class import FiniteCombinatorialClass
     21from sage.rings.integer import Integer
     22
     23def Family(indices, function = None, name = None, hidden_keys = [], hidden_function = None):
     24    r"""
     25    A Family is an associative container which models a family
     26    `(f_i)_{i \in I}`. Then, f[i] returns the element of the family
     27    indexed by i. Whenever available, set and combinatorial class
     28    operations (counting, iteration, listing) on the family are induced
     29    from those of the index set.
     30   
     31    There are several available implementations (classes) for different
     32    usages; Family serves as a factory, and will create instances of
     33    the appropriate classes depending on its arguments.
     34   
     35    EXAMPLES:
     36   
     37    In its simplest form, a list l or a tuple by itself is considered as the
     38    family `(l[i]_{i \in I})` where `I` is the range `0\dots,len(l)`. So
     39    Family(l) returns the corresponding family.
     40   
     41    ::
     42   
     43        sage: f = Family([1,2,3])
     44        sage: f
     45        Family (1, 2, 3)
     46        sage: f = Family((1,2,3))
     47        sage: f
     48        Family (1, 2, 3)
     49   
     50    A family can also be constructed from a dictionary t. The resulting
     51    family is very close to t, except that the elements of the family
     52    are the values of t. Here, we define the family `(f_i)_{i \in \{3,4,7\}}`
     53    with f_3='a', f_4='b', and f_7='d'::
     54   
     55        sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
     56        sage: f
     57        Finite family {3: 'a', 4: 'b', 7: 'd'}
     58        sage: f[7]
     59        'd'
     60        sage: len(f)
     61        3
     62        sage: list(f)
     63        ['a', 'b', 'd']
     64        sage: [ x for x in f ]
     65        ['a', 'b', 'd']
     66        sage: f.keys()
     67        [3, 4, 7]
     68        sage: 'b' in f 
     69        True
     70        sage: 'e' in f
     71        False
     72   
     73    A family can also be constructed by its index set `I` and
     74    a function `f`, as in `(f(i))_{i \in I}`::
     75   
     76        sage: f = Family([3,4,7], lambda i: 2*i)
     77        sage: f
     78        Finite family {3: 6, 4: 8, 7: 14}
     79        sage: f.keys()
     80        [3, 4, 7]
     81        sage: f[7]
     82        14
     83        sage: list(f)
     84        [6, 8, 14]
     85        sage: [x for x in f]
     86        [6, 8, 14]
     87        sage: len(f)
     88        3
     89   
     90    By default, if the index set is a list or a tuple, all images are
     91    computed right away, and stored in an internal dictionary::
     92
     93        sage: f = Family((3,4,7), lambda i: 2*i)
     94        sage: f
     95        Finite family {3: 6, 4: 8, 7: 14}
     96
     97    Note that this requires all the elements of the list to be
     98    hashable. One can ask instead for the images `f(i)` to be computed
     99    lazily, when needed::
     100   
     101        sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
     102        sage: f
     103        Lazy family (f(i))_{i in [3, 4, 7]}
     104        sage: f[7]
     105        14
     106        sage: list(f)
     107        [6, 8, 14]
     108        sage: [x for x in f]
     109        [6, 8, 14]
     110   
     111    This allows in particular for modeling infinite families::
     112   
     113        sage: f = Family(ZZ, lambda i: 2r*i)
     114        sage: f
     115        Lazy family (f(i))_{i in Integer Ring}
     116        sage: f.keys()
     117        Integer Ring
     118        sage: f[1]
     119        2
     120        sage: f[-5]
     121        -10
     122        sage: i = iter(f)
     123        sage: i.next(), i.next(), i.next(), i.next(), i.next()
     124        (0, 2, -2, 4, -4)
     125   
     126    Beware that for those kind of families len(f) is not supposed to
     127    work. As a replacement, use the .cardinality() method::
     128   
     129       sage: f = LazyFamily(Permutations(3), attrcall("to_lehmer_code"))
     130       sage: list(f)
     131       [[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0], [2, 0, 0], [2, 1, 0]]
     132       sage: f.cardinality()
     133       6
     134
     135    Caveat: Only certain families with lazy behavior can be pickled. In
     136    particular, only functions that work with Sage's pickle_function
     137    and unpickle_function (in sage.misc.fpickle) will correctly
     138    unpickle. The following two work::
     139
     140       sage: loads(dumps(LazyFamily(Permutations(3), lambda p: p.to_lehmer_code())))
     141       Lazy family (f(i))_{i in Standard permutations of 3}
     142
     143       sage: loads(dumps(LazyFamily(Permutations(3), attrcall("to_lehmer_code"))))
     144       Lazy family (f(i))_{i in Standard permutations of 3}
     145
     146    But this one dont::   
     147
     148       sage: def plus_n(n): return lambda x: x+n
     149       sage: loads(dumps(LazyFamily([1,2,3], plus_n(3))))
     150       Traceback (most recent call last):
     151       ...
     152       ValueError: Cannot pickle code objects from closures
     153       
     154    Finally, it can occasionally be useful to add some hidden elements
     155    in a family, which are accessible as f[i], but do not appear in the
     156    keys or the container operations.
     157   
     158    ::
     159   
     160        sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     161        sage: f
     162        Finite family {3: 6, 4: 8, 7: 14}
     163        sage: f.keys()
     164        [3, 4, 7]
     165        sage: f.hidden_keys()
     166        [2]
     167        sage: f[7]
     168        14
     169        sage: f[2]
     170        4
     171        sage: list(f)
     172        [6, 8, 14]
     173        sage: [x for x in f]
     174        [6, 8, 14]
     175        sage: len(f)
     176        3
     177   
     178    The following example illustrates when the function is actually
     179    called::
     180   
     181        sage: def compute_value(i):
     182        ...       print('computing 2*'+str(i))
     183        ...       return 2*i
     184        sage: f = Family([3,4,7], compute_value, hidden_keys=[2])
     185        computing 2*3
     186        computing 2*4
     187        computing 2*7
     188        sage: f
     189        Finite family {3: 6, 4: 8, 7: 14}
     190        sage: f.keys()
     191        [3, 4, 7]
     192        sage: f.hidden_keys()
     193        [2]
     194        sage: f[7]
     195        14
     196        sage: f[2]
     197        computing 2*2
     198        4
     199        sage: f[2]
     200        4
     201        sage: list(f)
     202        [6, 8, 14]
     203        sage: [x for x in f]
     204        [6, 8, 14]
     205        sage: len(f)
     206        3
     207   
     208    Here is a close variant where the function for the hidden keys is
     209    different from that for the other keys::
     210   
     211        sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2], hidden_function = lambda i: 3*i)
     212        sage: f
     213        Finite family {3: 6, 4: 8, 7: 14}
     214        sage: f.keys()
     215        [3, 4, 7]
     216        sage: f.hidden_keys()
     217        [2]
     218        sage: f[7]
     219        14
     220        sage: f[2]
     221        6
     222        sage: list(f)
     223        [6, 8, 14]
     224        sage: [x for x in f]
     225        [6, 8, 14]
     226        sage: len(f)
     227        3
     228   
     229    Family behaves the same way with FiniteCombinatorialClass instances
     230    and lists. This feature will eventually disappear when
     231    FiniteCombinatorialClass won't be needed anymore.
     232   
     233    ::
     234   
     235        sage: f = Family(FiniteCombinatorialClass([1,2,3]))
     236        sage: f
     237        Combinatorial class with elements in [1, 2, 3]
     238   
     239    ::
     240   
     241        sage: f = Family(FiniteCombinatorialClass([3,4,7]), lambda i: 2*i)
     242        sage: f
     243        Finite family {3: 6, 4: 8, 7: 14}
     244        sage: f.keys()
     245        [3, 4, 7]
     246        sage: f[7]
     247        14
     248        sage: list(f)
     249        [6, 8, 14]
     250        sage: [x for x in f]
     251        [6, 8, 14]
     252        sage: len(f)
     253        3
     254   
     255    TESTS::
     256   
     257        sage: f = Family({1:'a', 2:'b', 3:'c'})
     258        sage: f
     259        Finite family {1: 'a', 2: 'b', 3: 'c'}
     260        sage: f[2]
     261        'b'
     262        sage: loads(dumps(f)) == f
     263        True
     264   
     265    ::
     266   
     267        sage: f = Family(range(1,27), lambda i: chr(i+96))
     268        sage: f
     269            Finite family {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z'}
     270        sage: f[2]
     271        'b'
     272
     273    The factory ``Family`` is supposed to be idempotent. We test this feature here::
     274   
     275        sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     276        sage: g = Family(f)
     277        sage: f == g
     278        True
     279   
     280        sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2])
     281        sage: g = Family(f)
     282        sage: f == g
     283        True
     284
     285        sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
     286        sage: g = Family(f)
     287        sage: f == g
     288        True
     289
     290        sage: f = TrivialFamily([3,4,7])
     291        sage: g = Family(f)
     292        sage: f == g
     293        True
     294    """
     295    assert(type(hidden_keys) == list)
     296    if function is None and hidden_keys == []:
     297        if isinstance(indices, dict):
     298            return FiniteFamily(indices)
     299        if isinstance(indices, (list, tuple) ):
     300            return TrivialFamily(indices)
     301        if isinstance(indices, (FiniteCombinatorialClass,
     302                                FiniteFamily, LazyFamily, TrivialFamily) ):
     303            return indices
     304    else:
     305        if isinstance(indices, (list, tuple, FiniteCombinatorialClass) ):
     306            if not hidden_keys == []:
     307                if hidden_function is None:
     308                    hidden_function = function
     309                return FiniteFamilyWithHiddenKeys(dict([(i, function(i)) for i in indices]),
     310                                                  hidden_keys, hidden_function)
     311            else:
     312                return FiniteFamily(dict([(i, function(i)) for i in indices]), keys = indices)
     313        elif hidden_keys == [] and hidden_function is None:
     314            return LazyFamily(indices, function)
     315    raise NotImplementedError
     316
     317class AbstractFamily(CombinatorialClass):
     318    """
     319    The abstract class for family
     320
     321    Any family belongs to a class which inherits from ``AbstractFamily``.
     322    """
     323    def hidden_keys(self):
     324        """
     325        Returns the hidden keys of the family, if any.
     326       
     327        EXAMPLES::
     328       
     329            sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
     330            sage: f.hidden_keys()
     331            []
     332        """
     333        return []
     334
     335    def zip(self, f, other, name = None):
     336        """
     337        Given two families with same index set `I` (and same hidden
     338        keys if relevant), returns the family
     339        `( f(self[i], other[i]) )_{i \in I}`
     340       
     341        TODO: generalize to any number of families and merge with map?
     342       
     343        EXAMPLES::
     344       
     345            sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
     346            sage: g = Family({3: '1', 4: '2', 7: '3'})
     347            sage: h = f.zip(lambda x,y: x+y, g)
     348            sage: list(h)
     349            ['a1', 'b2', 'd3']
     350        """
     351        assert(self.keys() == other.keys())
     352        assert(self.hidden_keys() == other.hidden_keys())
     353        return Family(self.keys(), lambda i: f(self[i],other[i]), hidden_keys = self.hidden_keys(), name = name)
     354
     355    def map(self, f, name = None):
     356        """
     357        Returns the family `( f(\mathtt{self}[i]) )_{i \in I}`, where
     358        `I` is the index set of self.
     359       
     360        TODO: good name?
     361       
     362        EXAMPLES::
     363       
     364            sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
     365            sage: g = f.map(lambda x: x+'1')
     366            sage: list(g)
     367            ['a1', 'b1', 'd1']
     368        """
     369        return Family(self.keys(), lambda i: f(self[i]), hidden_keys = self.hidden_keys(), name = name)
     370
     371class FiniteFamily(AbstractFamily):
     372    r"""
     373    A FiniteFamily is an associative container which models a finite
     374    family `(f_i)_{i \in I}`. Its elements `f_i` are therefore
     375    its values. Instances should be created via the Family factory,
     376    which see for further examples and tests.
     377   
     378    EXAMPLES: We define the family `(f_i)_{i \in \{3,4,7\}}` with f_3=a,
     379    f_4=b, and f_7=d
     380   
     381    ::
     382   
     383        sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     384   
     385    Individual elements are accessible as in a usual dictionary::
     386   
     387        sage: f[7]
     388        'd'
     389   
     390    And the other usual dictionary operations are also available::
     391   
     392        sage: len(f)
     393        3
     394        sage: f.keys()
     395        [3, 4, 7]
     396   
     397    However f behaves as a container for the `f_i`'s::
     398   
     399        sage: list(f)
     400        ['a', 'b', 'd']
     401        sage: [ x for x in f ]
     402        ['a', 'b', 'd']
     403    """
     404
     405    def __init__(self, dictionary, keys = None):
     406        """
     407        TESTS::
     408       
     409            sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     410            sage: f == loads(dumps(f))
     411            True
     412
     413        Check for bug #5538::
     414
     415            sage: d = {1:"a", 3:"b", 4:"c"}
     416            sage: f = Family(d)
     417            sage: d[2] = 'DD'
     418            sage: f
     419            Finite family {1: 'a', 3: 'b', 4: 'c'}
     420            """
     421        # TODO: use keys to specify the order of the elements
     422        self.dictionary = dict(dictionary)
     423        self.keys = dictionary.keys
     424        self.values = dictionary.values
     425
     426    def __repr__(self):
     427        """
     428        EXAMPLES::
     429       
     430            sage: FiniteFamily({3: 'a'})
     431            Finite family {3: 'a'}
     432        """
     433        return "Finite family %s"%self.dictionary
     434
     435    def __contains__(self, x):
     436        """
     437        EXAMPLES::
     438       
     439            sage: f = FiniteFamily({3: 'a'})
     440            sage: 'a' in f
     441            True
     442            sage: 'b' in f
     443            False
     444        """
     445        return x in self.values()
     446
     447    def __len__(self):
     448        """
     449        Returns the number of elements in self.
     450
     451        EXAMPLES::
     452       
     453            sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     454            sage: len(f)
     455            3       
     456        """
     457        return len(self.dictionary)
     458   
     459    def cardinality(self):
     460        """
     461        Returns the number of elements in self.
     462       
     463        EXAMPLES::
     464       
     465            sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     466            sage: f.cardinality()
     467            3
     468        """
     469        return Integer(len(self.dictionary))
     470
     471    def __iter__(self):
     472        """
     473        EXAMPLES::
     474       
     475            sage: f = FiniteFamily({3: 'a'})
     476            sage: i = iter(f)
     477            sage: i.next()
     478            'a'
     479        """
     480        return iter(self.values())
     481
     482    def __getitem__(self, i):
     483        """
     484        Note that we can't just do self.__getitem__ =
     485        dictionary.__getitem__ in the __init__ method since Python
     486        queries the object's type/class for the special methods rather than
     487        querying the object itself.
     488       
     489        EXAMPLES::
     490       
     491            sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
     492            sage: f[3]
     493            'a'
     494        """
     495        return self.dictionary.__getitem__(i)
     496
     497    # For the pickle and copy modules
     498    def __getstate__(self):
     499        """
     500        TESTS::
     501       
     502            sage: f = FiniteFamily({3: 'a'})
     503            sage: f.__getstate__()
     504            {'dictionary': {3: 'a'}}
     505        """
     506        return {'dictionary': self.dictionary}
     507
     508    def __setstate__(self, state):
     509        """
     510        TESTS::
     511       
     512            sage: f = FiniteFamily({3: 'a'})
     513            sage: f.__setstate__({'dictionary': {4:'b'}})
     514            sage: f
     515            Finite family {4: 'b'}
     516        """
     517        self.__init__(state['dictionary'])
     518
     519class FiniteFamilyWithHiddenKeys(FiniteFamily):
     520    r"""
     521    A close variant of FiniteFamily where the family contains some
     522    hidden keys whose corresponding values are computed lazily (and
     523    remembered). Instances should be created via the Family factory,
     524    which see for examples and tests.
     525   
     526    Caveat: Only instances of this class whose functions are compatible
     527    with sage.misc.fpickle can be pickled.
     528    """
     529    def __init__(self, dictionary, hidden_keys, hidden_function):
     530        """
     531        EXAMPLES::
     532       
     533            sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2])
     534            sage: f == loads(dumps(f))
     535            True
     536        """
     537        FiniteFamily.__init__(self, dictionary)
     538        self._hidden_keys = hidden_keys
     539        self.hidden_function = hidden_function
     540        self.hidden_dictionary = {}
     541
     542        # would be better to define as usual method
     543        # any better to unset the def of __getitem__ by FiniteFamily?
     544        #self.__getitem__ = lambda i: dictionary[i] if dictionary.has_key(i) else hidden_dictionary[i]
     545
     546    def __getitem__(self, i):
     547        """
     548        EXAMPLES::
     549       
     550            sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     551            sage: f[3]
     552            6
     553            sage: f[2]
     554            4
     555            sage: f[5]
     556            Traceback (most recent call last):
     557            ...
     558            KeyError
     559        """
     560        if i in self.dictionary:
     561            return self.dictionary[i]
     562
     563        if i not in self.hidden_dictionary:
     564            if i not in self._hidden_keys:
     565                raise KeyError
     566            self.hidden_dictionary[i] = self.hidden_function(i)
     567
     568        return self.hidden_dictionary[i]
     569
     570    def hidden_keys(self):
     571        """
     572        Returns self's hidden keys.
     573       
     574        EXAMPLES::
     575       
     576            sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     577            sage: f.hidden_keys()
     578            [2]
     579        """
     580        return self._hidden_keys
     581
     582    def __getstate__(self):
     583        """
     584        TESTS::
     585       
     586            sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
     587            sage: d = f.__getstate__()
     588            sage: d['hidden_keys']
     589            [2]
     590        """
     591        from sage.misc.fpickle import pickle_function
     592        f = pickle_function(self.hidden_function)
     593        return {'dictionary': self.dictionary,
     594                'hidden_keys': self._hidden_keys,
     595                'hidden_dictionary': self.hidden_dictionary,
     596                'hidden_function': f}
     597
     598    def __setstate__(self, d):
     599        """
     600        TESTS::
     601       
     602            sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2])
     603            sage: d = f.__getstate__()
     604            sage: f = Family([4,5,6], lambda i: 2r*i, hidden_keys=[2])
     605            sage: f.__setstate__(d)
     606            sage: f.keys()
     607            [3, 4, 7]
     608            sage: f[3]
     609            6
     610           
     611            sage: f = LazyFamily(Permutations(3), lambda p: p.to_lehmer_code())
     612            sage: f == loads(dumps(f))
     613            True
     614
     615            sage: f = LazyFamily(Permutations(3), attrcall("to_lehmer_code"))
     616            sage: f == loads(dumps(f))
     617            True
     618        """
     619        hidden_function = d['hidden_function']
     620        if isinstance(hidden_function, str):
     621        # Let's assume that hidden_function is an unpicled function.             
     622            from sage.misc.fpickle import unpickle_function
     623            hidden_function = unpickle_function(hidden_function)
     624        self.__init__(d['dictionary'], d['hidden_keys'], hidden_function)
     625        self.hidden_dictionary = d['hidden_dictionary']
     626
     627
     628class LazyFamily(AbstractFamily):
     629    r"""
     630    A LazyFamily(I, f) is an associative container which models the
     631    (possibly infinite) family `(f(i))_{i \in I}`.
     632   
     633    Instances should be created via the Family factory, which see for
     634    examples and tests.
     635    """
     636    def __init__(self, set, function, name = "f"):
     637        """
     638        TESTS::
     639       
     640            sage: f = LazyFamily([3,4,7], lambda i: 2r*i); f
     641            Lazy family (f(i))_{i in [3, 4, 7]}
     642            sage: f == loads(dumps(f))
     643            True
     644
     645        Check for bug #5538::
     646       
     647            sage: l = [3,4,7]
     648            sage: f = LazyFamily(l, lambda i: 2r*i);
     649            sage: l[1] = 18
     650            sage: f
     651            Lazy family (f(i))_{i in [3, 4, 7]}
     652           
     653        """
     654        from copy import copy
     655        self.set = copy(set)
     656        self.name = name
     657        self.function = function
     658
     659    def __repr__(self):
     660        """
     661        EXAMPLES::
     662       
     663            sage: f = LazyFamily([3,4,7], lambda i: 2*i); f
     664            Lazy family (f(i))_{i in [3, 4, 7]}
     665        """
     666        return "Lazy family (%s(i))_{i in %s}"%(self.name,self.set)
     667
     668    def keys(self):
     669        """
     670        Returns self's keys.
     671       
     672        EXAMPLES::
     673       
     674            sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     675            sage: f.keys()
     676            [3, 4, 7]
     677        """
     678        return self.set
     679
     680    def cardinality(self):
     681        """
     682        Return the number of elements in self.
     683       
     684        EXAMPLES::
     685       
     686            sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     687            sage: f.cardinality()
     688            3
     689        """
     690        try:
     691            return Integer(len(self.set))
     692        except AttributeError:
     693            return self.set.cardinality()
     694   
     695    def __iter__(self):
     696        """
     697        EXAMPLES::
     698       
     699            sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     700            sage: [i for i in f]
     701            [6, 8, 14]
     702        """
     703        for i in self.set:
     704            yield self[i]
     705
     706    def __getitem__(self, i):
     707        """       
     708        EXAMPLES::
     709       
     710            sage: f = LazyFamily([3,4,7], lambda i: 2*i)
     711            sage: f[3]
     712            6
     713       
     714        TESTS::
     715       
     716            sage: f[5]
     717            10
     718        """
     719        return self.function(i)
     720
     721    def __getstate__(self):
     722        """       
     723        EXAMPLES::
     724       
     725            sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
     726            sage: d = f.__getstate__()
     727            sage: d['set']
     728            [3, 4, 7]
     729        """
     730        f = self.function
     731        # This should be done once for all by registering
     732        # sage.misc.fpickle.pickle_function to copy_reg
     733        if type(f) is type(Family): # TODO: where is the python `function` type?
     734            from sage.misc.fpickle import pickle_function
     735            f = pickle_function(f)
     736       
     737        return {'set': self.set,
     738                'name': self.name,
     739                'function': f}
     740
     741    def __setstate__(self, d):
     742        """
     743        EXAMPLES::
     744       
     745            sage: f = LazyFamily([3,4,7], lambda i: 2r*i)
     746            sage: d = f.__getstate__()
     747            sage: f = LazyFamily([4,5,6], lambda i: 2r*i)
     748            sage: f.__setstate__(d)
     749            sage: f.keys()
     750            [3, 4, 7]
     751            sage: f[3]
     752            6
     753        """
     754        function = d['function']
     755        if isinstance(function, str):
     756        # Let's assume that function is an unpicled function.             
     757            from sage.misc.fpickle import unpickle_function
     758            function = unpickle_function(function)
     759           
     760        self.__init__(d['set'], function, d['name'])
     761
     762
     763class TrivialFamily(AbstractFamily):
     764    r"""
     765    ``TrivialFamily(c)`` turn the container c into a family indexed by
     766    the set `{0,\dots, len(c)}`. The container `c` can be either a list or a
     767    tuple.
     768   
     769    Instances should be created via the Family factory, which see for
     770    examples and tests.
     771    """
     772    def __init__(self, set):
     773        """
     774        EXAMPLES::
     775       
     776            sage: f = TrivialFamily((3,4,7)); f
     777            Family (3, 4, 7)
     778            sage: f = TrivialFamily([3,4,7]); f
     779            Family (3, 4, 7)
     780            sage: f == loads(dumps(f))
     781            True
     782        """
     783        self.set = tuple(set)
     784
     785    def __repr__(self):
     786        """
     787        EXAMPLES::
     788       
     789            sage: f = TrivialFamily([3,4,7]); f
     790            Family (3, 4, 7)
     791        """
     792        return "Family %s"%((self.set),)
     793
     794    def keys(self):
     795        """
     796        Returns self's keys.
     797       
     798        EXAMPLES::
     799       
     800            sage: f = TrivialFamily([3,4,7])
     801            sage: f.keys()
     802            [0, 1, 2]
     803        """
     804        return range(len(self.set))
     805
     806    def cardinality(self):
     807        """
     808        Return the number of elements in self.
     809       
     810        EXAMPLES::
     811       
     812            sage: f = TrivialFamily([3,4,7])
     813            sage: f.cardinality()
     814            3
     815        """
     816        return Integer(len(self.set))
     817   
     818    def __iter__(self):
     819        """
     820        EXAMPLES::
     821       
     822            sage: f = TrivialFamily([3,4,7])
     823            sage: [i for i in f]
     824            [3, 4, 7]
     825        """
     826        for i in self.set:
     827            yield i
     828
     829    def __getitem__(self, i):
     830        """       
     831        EXAMPLES::
     832       
     833            sage: f = TrivialFamily([3,4,7])
     834            sage: f[1]
     835            4       
     836        """
     837        return self.set[i]
     838
     839    def __getstate__(self):
     840        """
     841        TESTS::
     842       
     843            sage: f = TrivialFamily([3,4,7])
     844            sage: f.__getstate__()
     845            {'set': (3, 4, 7)}
     846        """
     847        return {'set': self.set}
     848
     849    def __setstate__(self, state):
     850        """
     851        TESTS::
     852       
     853            sage: f = TrivialFamily([3,4,7])
     854            sage: f.__setstate__({'set': (2, 4, 8)})
     855            sage: f
     856            Family (2, 4, 8)
     857        """
     858        self.__init__(state['set'])