Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/sets/family.py
4096 views
1
"""
2
Families
3
4
A Family is an associative container which models a family
5
`(f_i)_{i \in I}`. Then, ``f[i]`` returns the element of the family indexed by
6
``i``. Whenever available, set and combinatorial class operations (counting,
7
iteration, listing) on the family are induced from those of the index
8
set. Families should be created through the :func:`Family` function.
9
10
AUTHORS:
11
12
- Nicolas Thiery (2008-02): initial release
13
14
- Florent Hivert (2008-04): various fixes, cleanups and improvements.
15
16
TESTS:
17
18
Check for workaround #12482 (shall be run in a fresh session)::
19
20
sage: P = Partitions(3)
21
sage: Family(P, lambda x: x).category() # used to return ``enumerated sets``
22
Category of finite enumerated sets
23
sage: Family(P, lambda x: x).category()
24
Category of finite enumerated sets
25
"""
26
#*****************************************************************************
27
# Copyright (C) 2008 Nicolas Thiery <nthiery at users.sf.net>,
28
# Mike Hansen <[email protected]>,
29
# Florent Hivert <[email protected]>
30
#
31
# Distributed under the terms of the GNU General Public License (GPL)
32
# http://www.gnu.org/licenses/
33
#*****************************************************************************
34
from sage.misc.cachefunc import cached_method
35
from sage.structure.parent import Parent
36
from sage.categories.enumerated_sets import EnumeratedSets
37
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
38
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
39
from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
40
from sage.misc.lazy_import import lazy_import
41
from sage.rings.integer import Integer
42
from sage.misc.misc import AttrCallObject
43
from warnings import warn
44
name_warn_message = "The keyword name for family has never been used and will be removed shortly. Please update your code."
45
46
def Family(indices, function = None, hidden_keys = [], hidden_function = None, lazy = False, name=None):
47
r"""
48
A Family is an associative container which models a family
49
`(f_i)_{i \in I}`. Then, f[i] returns the element of the family
50
indexed by i. Whenever available, set and combinatorial class
51
operations (counting, iteration, listing) on the family are induced
52
from those of the index set.
53
54
There are several available implementations (classes) for different
55
usages; Family serves as a factory, and will create instances of
56
the appropriate classes depending on its arguments.
57
58
EXAMPLES:
59
60
In its simplest form, a list l or a tuple by itself is considered as the
61
family `(l[i]_{i \in I})` where `I` is the range `0\dots,len(l)`. So
62
Family(l) returns the corresponding family::
63
64
sage: f = Family([1,2,3])
65
sage: f
66
Family (1, 2, 3)
67
sage: f = Family((1,2,3))
68
sage: f
69
Family (1, 2, 3)
70
71
Instead of a list you can as well pass any iterable object::
72
73
sage: f = Family(2*i+1 for i in [1,2,3]);
74
sage: f
75
Family (3, 5, 7)
76
77
A family can also be constructed from a dictionary t. The resulting
78
family is very close to t, except that the elements of the family
79
are the values of t. Here, we define the family `(f_i)_{i \in \{3,4,7\}}`
80
with f_3='a', f_4='b', and f_7='d'::
81
82
sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
83
sage: f
84
Finite family {3: 'a', 4: 'b', 7: 'd'}
85
sage: f[7]
86
'd'
87
sage: len(f)
88
3
89
sage: list(f)
90
['a', 'b', 'd']
91
sage: [ x for x in f ]
92
['a', 'b', 'd']
93
sage: f.keys()
94
[3, 4, 7]
95
sage: 'b' in f
96
True
97
sage: 'e' in f
98
False
99
100
A family can also be constructed by its index set `I` and
101
a function `f`, as in `(f(i))_{i \in I}`::
102
103
sage: f = Family([3,4,7], lambda i: 2*i)
104
sage: f
105
Finite family {3: 6, 4: 8, 7: 14}
106
sage: f.keys()
107
[3, 4, 7]
108
sage: f[7]
109
14
110
sage: list(f)
111
[6, 8, 14]
112
sage: [x for x in f]
113
[6, 8, 14]
114
sage: len(f)
115
3
116
117
By default, all images are computed right away, and stored in an internal
118
dictionary::
119
120
sage: f = Family((3,4,7), lambda i: 2*i)
121
sage: f
122
Finite family {3: 6, 4: 8, 7: 14}
123
124
Note that this requires all the elements of the list to be
125
hashable. One can ask instead for the images `f(i)` to be computed
126
lazily, when needed::
127
128
sage: f = Family([3,4,7], lambda i: 2*i, lazy=True)
129
sage: f
130
Lazy family (<lambda>(i))_{i in [3, 4, 7]}
131
sage: f[7]
132
14
133
sage: list(f)
134
[6, 8, 14]
135
sage: [x for x in f]
136
[6, 8, 14]
137
138
This allows in particular for modeling infinite families::
139
140
sage: f = Family(ZZ, lambda i: 2*i, lazy=True)
141
sage: f
142
Lazy family (<lambda>(i))_{i in Integer Ring}
143
sage: f.keys()
144
Integer Ring
145
sage: f[1]
146
2
147
sage: f[-5]
148
-10
149
sage: i = iter(f)
150
sage: i.next(), i.next(), i.next(), i.next(), i.next()
151
(0, 2, -2, 4, -4)
152
153
Note that the ``lazy`` keyword parameter is only needed to force
154
laziness. Usually it is automatically set to a correct default value (ie:
155
``False`` for finite data structures and ``True`` for enumerated sets::
156
157
sage: f == Family(ZZ, lambda i: 2*i)
158
True
159
160
Beware that for those kind of families len(f) is not supposed to
161
work. As a replacement, use the .cardinality() method::
162
163
sage: f = Family(Permutations(3), attrcall("to_lehmer_code"))
164
sage: list(f)
165
[[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0], [2, 0, 0], [2, 1, 0]]
166
sage: f.cardinality()
167
6
168
169
Caveat: Only certain families with lazy behavior can be pickled. In
170
particular, only functions that work with Sage's pickle_function
171
and unpickle_function (in sage.misc.fpickle) will correctly
172
unpickle. The following two work::
173
174
sage: f = Family(Permutations(3), lambda p: p.to_lehmer_code()); f
175
Lazy family (<lambda>(i))_{i in Standard permutations of 3}
176
sage: f == loads(dumps(f))
177
True
178
179
sage: f = Family(Permutations(3), attrcall("to_lehmer_code")); f
180
Lazy family (i.to_lehmer_code())_{i in Standard permutations of 3}
181
sage: f == loads(dumps(f))
182
True
183
184
But this one don't::
185
186
sage: def plus_n(n): return lambda x: x+n
187
sage: f = Family([1,2,3], plus_n(3), lazy=True); f
188
Lazy family (<lambda>(i))_{i in [1, 2, 3]}
189
sage: f == loads(dumps(f))
190
Traceback (most recent call last):
191
...
192
ValueError: Cannot pickle code objects from closures
193
194
Finally, it can occasionally be useful to add some hidden elements
195
in a family, which are accessible as f[i], but do not appear in the
196
keys or the container operations::
197
198
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
199
sage: f
200
Finite family {3: 6, 4: 8, 7: 14}
201
sage: f.keys()
202
[3, 4, 7]
203
sage: f.hidden_keys()
204
[2]
205
sage: f[7]
206
14
207
sage: f[2]
208
4
209
sage: list(f)
210
[6, 8, 14]
211
sage: [x for x in f]
212
[6, 8, 14]
213
sage: len(f)
214
3
215
216
The following example illustrates when the function is actually
217
called::
218
219
sage: def compute_value(i):
220
... print('computing 2*'+str(i))
221
... return 2*i
222
sage: f = Family([3,4,7], compute_value, hidden_keys=[2])
223
computing 2*3
224
computing 2*4
225
computing 2*7
226
sage: f
227
Finite family {3: 6, 4: 8, 7: 14}
228
sage: f.keys()
229
[3, 4, 7]
230
sage: f.hidden_keys()
231
[2]
232
sage: f[7]
233
14
234
sage: f[2]
235
computing 2*2
236
4
237
sage: f[2]
238
4
239
sage: list(f)
240
[6, 8, 14]
241
sage: [x for x in f]
242
[6, 8, 14]
243
sage: len(f)
244
3
245
246
Here is a close variant where the function for the hidden keys is
247
different from that for the other keys::
248
249
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2], hidden_function = lambda i: 3*i)
250
sage: f
251
Finite family {3: 6, 4: 8, 7: 14}
252
sage: f.keys()
253
[3, 4, 7]
254
sage: f.hidden_keys()
255
[2]
256
sage: f[7]
257
14
258
sage: f[2]
259
6
260
sage: list(f)
261
[6, 8, 14]
262
sage: [x for x in f]
263
[6, 8, 14]
264
sage: len(f)
265
3
266
267
Family accept finite and infinite EnumeratedSets as input::
268
269
sage: f = Family(FiniteEnumeratedSet([1,2,3]))
270
sage: f
271
Family (1, 2, 3)
272
sage: from sage.categories.examples.infinite_enumerated_sets import NonNegativeIntegers
273
sage: f = Family(NonNegativeIntegers())
274
sage: f
275
Family (An example of an infinite enumerated set: the non negative integers)
276
277
::
278
279
sage: f = Family(FiniteEnumeratedSet([3,4,7]), lambda i: 2*i)
280
sage: f
281
Finite family {3: 6, 4: 8, 7: 14}
282
sage: f.keys()
283
{3, 4, 7}
284
sage: f[7]
285
14
286
sage: list(f)
287
[6, 8, 14]
288
sage: [x for x in f]
289
[6, 8, 14]
290
sage: len(f)
291
3
292
293
TESTS::
294
295
sage: f = Family({1:'a', 2:'b', 3:'c'})
296
sage: f
297
Finite family {1: 'a', 2: 'b', 3: 'c'}
298
sage: f[2]
299
'b'
300
sage: loads(dumps(f)) == f
301
True
302
303
::
304
305
sage: f = Family({1:'a', 2:'b', 3:'c'}, lazy=True)
306
Traceback (most recent call last):
307
ValueError: lazy keyword only makes sense together with function keyword !
308
309
::
310
311
sage: f = Family(range(1,27), lambda i: chr(i+96))
312
sage: f
313
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'}
314
sage: f[2]
315
'b'
316
317
The factory ``Family`` is supposed to be idempotent. We test this feature here::
318
319
sage: from sage.sets.family import FiniteFamily, LazyFamily, TrivialFamily
320
sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
321
sage: g = Family(f)
322
sage: f == g
323
True
324
325
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
326
sage: g = Family(f)
327
sage: f == g
328
True
329
330
sage: f = LazyFamily([3,4,7], lambda i: 2*i)
331
sage: g = Family(f)
332
sage: f == g
333
True
334
335
sage: f = TrivialFamily([3,4,7])
336
sage: g = Family(f)
337
sage: f == g
338
True
339
340
The family should keep the order of the keys::
341
342
sage: f = Family(["c", "a", "b"], lambda x: x+x)
343
sage: list(f)
344
['cc', 'aa', 'bb']
345
"""
346
347
if name is not None:
348
warn(name_warn_message)
349
assert(type(hidden_keys) == list)
350
assert(isinstance(lazy, bool))
351
352
if hidden_keys == []:
353
if hidden_function is not None:
354
raise ValueError, "hidden_function keyword only makes sense together with hidden_keys keyword !"
355
elif function is None:
356
if lazy:
357
raise ValueError, "lazy keyword only makes sense together with function keyword !"
358
if isinstance(indices, dict):
359
return FiniteFamily(indices)
360
if isinstance(indices, (list, tuple) ):
361
return TrivialFamily(indices)
362
if isinstance(indices, (FiniteFamily, LazyFamily, TrivialFamily) ):
363
return indices
364
from sage.combinat.combinat import CombinatorialClass # workaround #12482
365
if (indices in EnumeratedSets()
366
or isinstance(indices, CombinatorialClass)):
367
return EnumeratedFamily(indices)
368
if hasattr(indices, "__iter__"):
369
return TrivialFamily(indices)
370
elif ( isinstance(indices, (list, tuple, FiniteEnumeratedSet) )
371
and not lazy):
372
return FiniteFamily(dict([(i, function(i)) for i in indices]),
373
keys = indices)
374
else:
375
return LazyFamily(indices, function)
376
else:
377
if lazy:
378
raise ValueError, "lazy keyword is incompatible with hidden keys !"
379
if hidden_function is None:
380
hidden_function = function
381
return FiniteFamilyWithHiddenKeys(dict([(i, function(i)) for i in indices]),
382
hidden_keys, hidden_function)
383
384
raise NotImplementedError
385
386
class AbstractFamily(Parent):
387
"""
388
The abstract class for family
389
390
Any family belongs to a class which inherits from ``AbstractFamily``.
391
"""
392
def hidden_keys(self):
393
"""
394
Returns the hidden keys of the family, if any.
395
396
EXAMPLES::
397
398
sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
399
sage: f.hidden_keys()
400
[]
401
"""
402
return []
403
404
def zip(self, f, other, name = None):
405
"""
406
Given two families with same index set `I` (and same hidden
407
keys if relevant), returns the family
408
`( f(self[i], other[i]) )_{i \in I}`
409
410
TODO: generalize to any number of families and merge with map?
411
412
EXAMPLES::
413
414
sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
415
sage: g = Family({3: '1', 4: '2', 7: '3'})
416
sage: h = f.zip(lambda x,y: x+y, g)
417
sage: list(h)
418
['a1', 'b2', 'd3']
419
"""
420
assert(self.keys() == other.keys())
421
assert(self.hidden_keys() == other.hidden_keys())
422
if name is not None:
423
warn(name_warn_message)
424
return Family(self.keys(), lambda i: f(self[i],other[i]), hidden_keys = self.hidden_keys())
425
426
def map(self, f, name = None):
427
"""
428
Returns the family `( f(\mathtt{self}[i]) )_{i \in I}`, where
429
`I` is the index set of self.
430
431
TODO: good name?
432
433
EXAMPLES::
434
435
sage: f = Family({3: 'a', 4: 'b', 7: 'd'})
436
sage: g = f.map(lambda x: x+'1')
437
sage: list(g)
438
['a1', 'b1', 'd1']
439
"""
440
if name is not None:
441
warn(name_warn_message)
442
return Family(self.keys(), lambda i: f(self[i]), hidden_keys = self.hidden_keys())
443
444
# temporary; tested by TestSuite.
445
_an_element_ = EnumeratedSets.ParentMethods._an_element_
446
447
@cached_method
448
def inverse_family(self):
449
"""
450
Returns the inverse family, with keys and values
451
exchanged. This presumes that there are no duplicate values in
452
``self``.
453
454
This default implementation is not lazy and therefore will
455
only work with not too big finite families. It is also cached
456
for the same reason.
457
458
sage: Family({3: 'a', 4: 'b', 7: 'd'}).inverse_family()
459
Finite family {'a': 3, 'b': 4, 'd': 7}
460
461
sage: Family((3,4,7)).inverse_family()
462
Finite family {3: 0, 4: 1, 7: 2}
463
464
"""
465
return Family( dict( (self[k], k) for k in self.keys()) )
466
467
class FiniteFamily(AbstractFamily):
468
r"""
469
A FiniteFamily is an associative container which models a finite
470
family `(f_i)_{i \in I}`. Its elements `f_i` are therefore
471
its values. Instances should be created via the Family factory,
472
which see for further examples and tests.
473
474
EXAMPLES: We define the family `(f_i)_{i \in \{3,4,7\}}` with f_3=a,
475
f_4=b, and f_7=d::
476
477
sage: from sage.sets.family import FiniteFamily
478
sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
479
480
Individual elements are accessible as in a usual dictionary::
481
482
sage: f[7]
483
'd'
484
485
And the other usual dictionary operations are also available::
486
487
sage: len(f)
488
3
489
sage: f.keys()
490
[3, 4, 7]
491
492
However f behaves as a container for the `f_i`'s::
493
494
sage: list(f)
495
['a', 'b', 'd']
496
sage: [ x for x in f ]
497
['a', 'b', 'd']
498
499
The order of the elements can be specified using the ``keys`` optional argument::
500
501
sage: f = FiniteFamily({"a": "aa", "b": "bb", "c" : "cc" }, keys = ["c", "a", "b"])
502
sage: list(f)
503
['cc', 'aa', 'bb']
504
505
"""
506
507
def __init__(self, dictionary, keys = None):
508
"""
509
TESTS::
510
511
sage: from sage.sets.family import FiniteFamily
512
sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
513
sage: TestSuite(f).run()
514
515
Check for bug #5538::
516
517
sage: d = {1:"a", 3:"b", 4:"c"}
518
sage: f = Family(d)
519
sage: d[2] = 'DD'
520
sage: f
521
Finite family {1: 'a', 3: 'b', 4: 'c'}
522
"""
523
# TODO: use keys to specify the order of the elements
524
Parent.__init__(self, category = FiniteEnumeratedSets())
525
self._dictionary = dict(dictionary)
526
self._keys = keys
527
if keys is None:
528
# Note: this overrides the two methods keys and values!
529
self.keys = dictionary.keys
530
self.values = dictionary.values
531
532
def keys(self):
533
"""
534
Returns the index set of this family
535
536
EXAMPLES::
537
538
sage: f = Family(["c", "a", "b"], lambda x: x+x)
539
sage: f.keys()
540
['c', 'a', 'b']
541
"""
542
return self._keys
543
544
def values(self):
545
"""
546
Returns the elements of this family
547
548
EXAMPLES::
549
550
sage: f = Family(["c", "a", "b"], lambda x: x+x)
551
sage: f.values()
552
['cc', 'aa', 'bb']
553
"""
554
return [ self._dictionary[key] for key in self._keys ]
555
556
def has_key(self, k):
557
"""
558
Returns whether ``k`` is a key of ``self``
559
560
EXAMPLES::
561
562
sage: Family({"a":1, "b":2, "c":3}).has_key("a")
563
True
564
sage: Family({"a":1, "b":2, "c":3}).has_key("d")
565
False
566
"""
567
return self._dictionary.has_key(k)
568
569
def __eq__(self, other):
570
"""
571
EXAMPLES::
572
573
sage: f = Family({1:'a', 2:'b', 3:'c'})
574
sage: g = Family({1:'a', 2:'b', 3:'c'})
575
sage: f == g
576
True
577
578
TESTS::
579
580
sage: from sage.sets.family import FiniteFamily
581
582
sage: f1 = FiniteFamily({1:'a', 2:'b', 3:'c'}, keys = [1,2,3])
583
sage: g1 = FiniteFamily({1:'a', 2:'b', 3:'c'}, keys = [1,2,3])
584
sage: h1 = FiniteFamily({1:'a', 2:'b', 3:'c'}, keys = [2,1,3])
585
586
sage: f1 == g1
587
True
588
sage: f1 == h1
589
False
590
sage: f1 == f
591
False
592
"""
593
return (isinstance(other, self.__class__) and
594
self._keys == other._keys and
595
self._dictionary == other._dictionary)
596
597
def _repr_(self):
598
"""
599
EXAMPLES::
600
601
sage: from sage.sets.family import FiniteFamily
602
sage: FiniteFamily({3: 'a'}) # indirect doctest
603
Finite family {3: 'a'}
604
"""
605
return "Finite family %s"%self._dictionary
606
607
def __contains__(self, x):
608
"""
609
EXAMPLES::
610
611
sage: from sage.sets.family import FiniteFamily
612
sage: f = FiniteFamily({3: 'a'})
613
sage: 'a' in f
614
True
615
sage: 'b' in f
616
False
617
"""
618
return x in self.values()
619
620
def __len__(self):
621
"""
622
Returns the number of elements in self.
623
624
EXAMPLES::
625
626
sage: from sage.sets.family import FiniteFamily
627
sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
628
sage: len(f)
629
3
630
"""
631
return len(self._dictionary)
632
633
def cardinality(self):
634
"""
635
Returns the number of elements in self.
636
637
EXAMPLES::
638
639
sage: from sage.sets.family import FiniteFamily
640
sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
641
sage: f.cardinality()
642
3
643
"""
644
return Integer(len(self._dictionary))
645
646
def __iter__(self):
647
"""
648
EXAMPLES::
649
650
sage: from sage.sets.family import FiniteFamily
651
sage: f = FiniteFamily({3: 'a'})
652
sage: i = iter(f)
653
sage: i.next()
654
'a'
655
"""
656
return iter(self.values())
657
658
def __getitem__(self, i):
659
"""
660
Note that we can't just do self.__getitem__ =
661
dictionary.__getitem__ in the __init__ method since Python
662
queries the object's type/class for the special methods rather than
663
querying the object itself.
664
665
EXAMPLES::
666
667
sage: from sage.sets.family import FiniteFamily
668
sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'})
669
sage: f[3]
670
'a'
671
"""
672
return self._dictionary.__getitem__(i)
673
674
# For the pickle and copy modules
675
def __getstate__(self):
676
"""
677
TESTS::
678
679
sage: from sage.sets.family import FiniteFamily
680
sage: f = FiniteFamily({3: 'a'})
681
sage: f.__getstate__()
682
{'keys': None, 'dictionary': {3: 'a'}}
683
"""
684
return {'dictionary': self._dictionary, 'keys': self._keys}
685
686
def __setstate__(self, state):
687
"""
688
TESTS::
689
690
sage: from sage.sets.family import FiniteFamily
691
sage: f = FiniteFamily({3: 'a'})
692
sage: f.__setstate__({'dictionary': {4:'b'}})
693
sage: f
694
Finite family {4: 'b'}
695
"""
696
self.__init__(state['dictionary'], keys = state.get("keys"))
697
698
class FiniteFamilyWithHiddenKeys(FiniteFamily):
699
r"""
700
A close variant of FiniteFamily where the family contains some
701
hidden keys whose corresponding values are computed lazily (and
702
remembered). Instances should be created via the Family factory,
703
which see for examples and tests.
704
705
Caveat: Only instances of this class whose functions are compatible
706
with sage.misc.fpickle can be pickled.
707
"""
708
def __init__(self, dictionary, hidden_keys, hidden_function):
709
"""
710
EXAMPLES::
711
712
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
713
sage: TestSuite(f).run()
714
"""
715
FiniteFamily.__init__(self, dictionary)
716
self._hidden_keys = hidden_keys
717
self.hidden_function = hidden_function
718
self.hidden_dictionary = {}
719
720
# would be better to define as usual method
721
# any better to unset the def of __getitem__ by FiniteFamily?
722
#self.__getitem__ = lambda i: dictionary[i] if dictionary.has_key(i) else hidden_dictionary[i]
723
724
def __getitem__(self, i):
725
"""
726
EXAMPLES::
727
728
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
729
sage: f[3]
730
6
731
sage: f[2]
732
4
733
sage: f[5]
734
Traceback (most recent call last):
735
...
736
KeyError
737
"""
738
if i in self._dictionary:
739
return self._dictionary[i]
740
741
if i not in self.hidden_dictionary:
742
if i not in self._hidden_keys:
743
raise KeyError
744
self.hidden_dictionary[i] = self.hidden_function(i)
745
746
return self.hidden_dictionary[i]
747
748
def hidden_keys(self):
749
"""
750
Returns self's hidden keys.
751
752
EXAMPLES::
753
754
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
755
sage: f.hidden_keys()
756
[2]
757
"""
758
return self._hidden_keys
759
760
def __getstate__(self):
761
"""
762
TESTS::
763
764
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
765
sage: d = f.__getstate__()
766
sage: d['hidden_keys']
767
[2]
768
"""
769
from sage.misc.fpickle import pickle_function
770
f = pickle_function(self.hidden_function)
771
return {'dictionary': self._dictionary,
772
'hidden_keys': self._hidden_keys,
773
'hidden_dictionary': self.hidden_dictionary,
774
'hidden_function': f}
775
776
def __setstate__(self, d):
777
"""
778
TESTS::
779
780
sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2])
781
sage: d = f.__getstate__()
782
sage: f = Family([4,5,6], lambda i: 2*i, hidden_keys=[2])
783
sage: f.__setstate__(d)
784
sage: f.keys()
785
[3, 4, 7]
786
sage: f[3]
787
6
788
"""
789
hidden_function = d['hidden_function']
790
if isinstance(hidden_function, str):
791
# Let's assume that hidden_function is an unpickled function.
792
from sage.misc.fpickle import unpickle_function
793
hidden_function = unpickle_function(hidden_function)
794
self.__init__(d['dictionary'], d['hidden_keys'], hidden_function)
795
self.hidden_dictionary = d['hidden_dictionary']
796
797
798
class LazyFamily(AbstractFamily):
799
r"""
800
A LazyFamily(I, f) is an associative container which models the
801
(possibly infinite) family `(f(i))_{i \in I}`.
802
803
Instances should be created via the Family factory, which see for
804
examples and tests.
805
"""
806
def __init__(self, set, function, name=None):
807
"""
808
TESTS::
809
810
sage: from sage.sets.family import LazyFamily
811
sage: f = LazyFamily([3,4,7], lambda i: 2*i); f
812
Lazy family (<lambda>(i))_{i in [3, 4, 7]}
813
sage: TestSuite(f).run() # __contains__ is not implemented
814
Failure ...
815
The following tests failed: _test_an_element, _test_enumerated_set_contains, _test_some_elements
816
817
Check for bug #5538::
818
819
sage: l = [3,4,7]
820
sage: f = LazyFamily(l, lambda i: 2*i);
821
sage: l[1] = 18
822
sage: f
823
Lazy family (<lambda>(i))_{i in [3, 4, 7]}
824
"""
825
from sage.combinat.combinat import CombinatorialClass # workaround #12482
826
827
if set in FiniteEnumeratedSets():
828
category = FiniteEnumeratedSets()
829
elif set in InfiniteEnumeratedSets():
830
category = InfiniteEnumeratedSets()
831
elif isinstance(set, (list, tuple, CombinatorialClass)):
832
category = FiniteEnumeratedSets()
833
else:
834
category = EnumeratedSets()
835
836
Parent.__init__(self, category = category)
837
if name is not None:
838
warn(name_warn_message)
839
from copy import copy
840
self.set = copy(set)
841
self.function = function
842
843
844
def __eq__(self, other):
845
"""
846
WARNING: Since there is no way to compare function, we only compare
847
their name.
848
849
TESTS::
850
851
sage: from sage.sets.family import LazyFamily
852
sage: fun = lambda i: 2*i
853
sage: f = LazyFamily([3,4,7], fun)
854
sage: g = LazyFamily([3,4,7], fun)
855
sage: f == g
856
True
857
"""
858
from sage.misc.fpickle import pickle_function
859
if not isinstance(other, self.__class__):
860
return False
861
if not self.set == other.set:
862
return False
863
return self.__repr__() == other.__repr__()
864
865
def _repr_(self):
866
"""
867
EXAMPLES::
868
869
sage: from sage.sets.family import LazyFamily
870
sage: def fun(i): 2*i
871
sage: f = LazyFamily([3,4,7], fun); f # indirect doctest
872
Lazy family (fun(i))_{i in [3, 4, 7]}
873
874
sage: f = Family(Permutations(3), attrcall("to_lehmer_code"), lazy=True); f
875
Lazy family (i.to_lehmer_code())_{i in Standard permutations of 3}
876
877
sage: f = LazyFamily([3,4,7], lambda i: 2*i); f
878
Lazy family (<lambda>(i))_{i in [3, 4, 7]}
879
880
TESTS:
881
882
Check that a using a class as the function is correctly handled::
883
884
sage: Family(NonNegativeIntegers(), PerfectMatchings)
885
Lazy family (<class 'sage.combinat.perfect_matching.PerfectMatchings'>(i))_{i in Non negative integers}
886
"""
887
if isinstance(self.function, type(lambda x:1)):
888
name = self.function.__name__
889
name = name+"(i)"
890
else:
891
name = repr(self.function)
892
if isinstance(self.function, AttrCallObject):
893
name = "i"+name[1:]
894
else:
895
name = name+"(i)"
896
return "Lazy family (%s)_{i in %s}"%(name,self.set)
897
898
def keys(self):
899
"""
900
Returns self's keys.
901
902
EXAMPLES::
903
904
sage: from sage.sets.family import LazyFamily
905
sage: f = LazyFamily([3,4,7], lambda i: 2*i)
906
sage: f.keys()
907
[3, 4, 7]
908
"""
909
return self.set
910
911
def cardinality(self):
912
"""
913
Return the number of elements in self.
914
915
EXAMPLES::
916
917
sage: from sage.sets.family import LazyFamily
918
sage: f = LazyFamily([3,4,7], lambda i: 2*i)
919
sage: f.cardinality()
920
3
921
sage: from sage.categories.examples.infinite_enumerated_sets import NonNegativeIntegers
922
sage: l = LazyFamily(NonNegativeIntegers(), lambda i: 2*i)
923
sage: l.cardinality()
924
+Infinity
925
"""
926
try:
927
return Integer(len(self.set))
928
except (AttributeError, NotImplementedError):
929
return self.set.cardinality()
930
931
def __iter__(self):
932
"""
933
EXAMPLES::
934
935
sage: from sage.sets.family import LazyFamily
936
sage: f = LazyFamily([3,4,7], lambda i: 2*i)
937
sage: [i for i in f]
938
[6, 8, 14]
939
"""
940
for i in self.set:
941
yield self[i]
942
943
def __getitem__(self, i):
944
"""
945
EXAMPLES::
946
947
sage: from sage.sets.family import LazyFamily
948
sage: f = LazyFamily([3,4,7], lambda i: 2*i)
949
sage: f[3]
950
6
951
952
TESTS::
953
954
sage: f[5]
955
10
956
"""
957
return self.function(i)
958
959
def __getstate__(self):
960
"""
961
EXAMPLES::
962
963
sage: from sage.sets.family import LazyFamily
964
sage: f = LazyFamily([3,4,7], lambda i: 2*i)
965
sage: d = f.__getstate__()
966
sage: d['set']
967
[3, 4, 7]
968
969
sage: f = LazyFamily(Permutations(3), lambda p: p.to_lehmer_code())
970
sage: f == loads(dumps(f))
971
True
972
973
sage: f = LazyFamily(Permutations(3), attrcall("to_lehmer_code"))
974
sage: f == loads(dumps(f))
975
True
976
"""
977
f = self.function
978
# This should be done once for all by registering
979
# sage.misc.fpickle.pickle_function to copy_reg
980
if type(f) is type(Family): # TODO: where is the python `function` type?
981
from sage.misc.fpickle import pickle_function
982
f = pickle_function(f)
983
984
return {'set': self.set,
985
'function': f}
986
987
def __setstate__(self, d):
988
"""
989
EXAMPLES::
990
991
sage: from sage.sets.family import LazyFamily
992
sage: f = LazyFamily([3,4,7], lambda i: 2*i)
993
sage: d = f.__getstate__()
994
sage: f = LazyFamily([4,5,6], lambda i: 2*i)
995
sage: f.__setstate__(d)
996
sage: f.keys()
997
[3, 4, 7]
998
sage: f[3]
999
6
1000
"""
1001
function = d['function']
1002
if isinstance(function, str):
1003
# Let's assume that function is an unpickled function.
1004
from sage.misc.fpickle import unpickle_function
1005
function = unpickle_function(function)
1006
1007
self.__init__(d['set'], function)
1008
1009
1010
class TrivialFamily(AbstractFamily):
1011
r"""
1012
``TrivialFamily(c)`` turn the container c into a family indexed by
1013
the set `{0, \dots, len(c)}`. The container `c` can be either a list or a
1014
tuple.
1015
1016
Instances should be created via the Family factory, which see for
1017
examples and tests.
1018
"""
1019
def __init__(self, enumeration):
1020
"""
1021
EXAMPLES::
1022
1023
sage: from sage.sets.family import TrivialFamily
1024
sage: f = TrivialFamily((3,4,7)); f
1025
Family (3, 4, 7)
1026
sage: f = TrivialFamily([3,4,7]); f
1027
Family (3, 4, 7)
1028
sage: TestSuite(f).run()
1029
"""
1030
Parent.__init__(self, category = FiniteEnumeratedSets())
1031
self._enumeration = tuple(enumeration)
1032
1033
def __eq__(self, other):
1034
"""
1035
TESTS::
1036
1037
sage: f = Family((3,4,7))
1038
sage: g = Family([3,4,7])
1039
sage: f == g
1040
True
1041
"""
1042
return (isinstance(other, self.__class__) and
1043
self._enumeration == other._enumeration)
1044
1045
def _repr_(self):
1046
"""
1047
EXAMPLES::
1048
1049
sage: from sage.sets.family import TrivialFamily
1050
sage: f = TrivialFamily([3,4,7]); f # indirect doctest
1051
Family (3, 4, 7)
1052
"""
1053
return "Family %s"%((self._enumeration),)
1054
1055
def keys(self):
1056
"""
1057
Returns self's keys.
1058
1059
EXAMPLES::
1060
1061
sage: from sage.sets.family import TrivialFamily
1062
sage: f = TrivialFamily([3,4,7])
1063
sage: f.keys()
1064
[0, 1, 2]
1065
"""
1066
return range(len(self._enumeration))
1067
1068
def cardinality(self):
1069
"""
1070
Return the number of elements in self.
1071
1072
EXAMPLES::
1073
1074
sage: from sage.sets.family import TrivialFamily
1075
sage: f = TrivialFamily([3,4,7])
1076
sage: f.cardinality()
1077
3
1078
"""
1079
return Integer(len(self._enumeration))
1080
1081
def __iter__(self):
1082
"""
1083
EXAMPLES::
1084
1085
sage: from sage.sets.family import TrivialFamily
1086
sage: f = TrivialFamily([3,4,7])
1087
sage: [i for i in f]
1088
[3, 4, 7]
1089
"""
1090
return iter(self._enumeration)
1091
1092
def __contains__(self, x):
1093
"""
1094
EXAMPLES::
1095
1096
sage: from sage.sets.family import TrivialFamily
1097
sage: f = TrivialFamily([3,4,7])
1098
sage: 3 in f
1099
True
1100
sage: 5 in f
1101
False
1102
"""
1103
return x in self._enumeration
1104
1105
def __getitem__(self, i):
1106
"""
1107
EXAMPLES::
1108
1109
sage: from sage.sets.family import TrivialFamily
1110
sage: f = TrivialFamily([3,4,7])
1111
sage: f[1]
1112
4
1113
"""
1114
return self._enumeration[i]
1115
1116
def __getstate__(self):
1117
"""
1118
TESTS::
1119
1120
sage: from sage.sets.family import TrivialFamily
1121
sage: f = TrivialFamily([3,4,7])
1122
sage: f.__getstate__()
1123
{'_enumeration': (3, 4, 7)}
1124
"""
1125
return {'_enumeration': self._enumeration}
1126
1127
def __setstate__(self, state):
1128
"""
1129
TESTS::
1130
1131
sage: from sage.sets.family import TrivialFamily
1132
sage: f = TrivialFamily([3,4,7])
1133
sage: f.__setstate__({'_enumeration': (2, 4, 8)})
1134
sage: f
1135
Family (2, 4, 8)
1136
"""
1137
self.__init__(state['_enumeration'])
1138
1139
1140
1141
from sage.categories.examples.infinite_enumerated_sets import NonNegativeIntegers
1142
from sage.rings.infinity import Infinity
1143
1144
class EnumeratedFamily(LazyFamily):
1145
r"""
1146
``EnumeratedFamily(c)`` turn the enumerated set c into a family indexed by
1147
the set `{0,\dots, c.cardinality()}`.
1148
1149
Instances should be created via the Family factory, which see for
1150
examples and tests.
1151
"""
1152
def __init__(self, enumset):
1153
"""
1154
EXAMPLES::
1155
1156
sage: from sage.sets.family import EnumeratedFamily
1157
sage: f = EnumeratedFamily(Permutations(3))
1158
sage: TestSuite(f).run()
1159
1160
sage: from sage.categories.examples.infinite_enumerated_sets import NonNegativeIntegers
1161
sage: f = Family(NonNegativeIntegers())
1162
sage: TestSuite(f).run()
1163
"""
1164
if enumset.cardinality() == Infinity:
1165
baseset=NonNegativeIntegers()
1166
else:
1167
baseset=xrange(enumset.cardinality())
1168
LazyFamily.__init__(self, baseset, enumset.unrank)
1169
self.enumset = enumset
1170
1171
def __eq__(self, other):
1172
"""
1173
EXAMPLES::
1174
1175
sage: f = Family(Permutations(3))
1176
sage: g = Family(Permutations(3))
1177
sage: f == g
1178
True
1179
"""
1180
return (isinstance(other, self.__class__) and
1181
self.enumset == other.enumset)
1182
1183
def __repr__(self):
1184
"""
1185
EXAMPLES::
1186
1187
sage: f = Family(Permutations(3)); f # indirect doctest
1188
Family (Standard permutations of 3)
1189
1190
sage: from sage.categories.examples.infinite_enumerated_sets import NonNegativeIntegers
1191
sage: f = Family(NonNegativeIntegers()); f
1192
Family (An example of an infinite enumerated set: the non negative integers)
1193
"""
1194
# return "Family ((%s)[i])_(i=1...%s)"%(self.enumset, self.enumset.cardinality())
1195
if isinstance(self.enumset, FiniteEnumeratedSet):
1196
return "Family %s"%(self.enumset._elements,)
1197
return "Family (%s)"%(self.enumset)
1198
1199
def __contains__(self, x):
1200
"""
1201
EXAMPLES::
1202
1203
sage: f = Family(Permutations(3))
1204
sage: f.keys()
1205
Standard permutations of 3
1206
sage: [2,1,3] in f
1207
True
1208
"""
1209
return x in self.enumset
1210
1211
1212
def keys(self):
1213
"""
1214
Returns self's keys.
1215
1216
EXAMPLES::
1217
1218
sage: from sage.sets.family import EnumeratedFamily
1219
sage: f = EnumeratedFamily(Permutations(3))
1220
sage: f.keys()
1221
Standard permutations of 3
1222
1223
sage: from sage.categories.examples.infinite_enumerated_sets import NonNegativeIntegers
1224
sage: f = Family(NonNegativeIntegers())
1225
sage: f.keys()
1226
An example of an infinite enumerated set: the non negative integers
1227
"""
1228
return self.enumset
1229
1230
def cardinality(self):
1231
"""
1232
Return the number of elements in self.
1233
1234
EXAMPLES::
1235
1236
sage: from sage.sets.family import EnumeratedFamily
1237
sage: f = EnumeratedFamily(Permutations(3))
1238
sage: f.cardinality()
1239
6
1240
1241
sage: from sage.categories.examples.infinite_enumerated_sets import NonNegativeIntegers
1242
sage: f = Family(NonNegativeIntegers())
1243
sage: f.cardinality()
1244
+Infinity
1245
"""
1246
return self.enumset.cardinality()
1247
1248
def __iter__(self):
1249
"""
1250
EXAMPLES::
1251
1252
sage: from sage.sets.family import EnumeratedFamily
1253
sage: f = EnumeratedFamily(Permutations(3))
1254
sage: [i for i in f]
1255
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
1256
"""
1257
for i in self.enumset:
1258
yield i
1259
1260
def __getitem__(self, i):
1261
"""
1262
EXAMPLES::
1263
1264
sage: from sage.sets.family import EnumeratedFamily
1265
sage: f = EnumeratedFamily(Permutations(3));
1266
sage: f[1]
1267
[1, 3, 2]
1268
"""
1269
return self.enumset.unrank(i)
1270
1271
def __getstate__(self):
1272
"""
1273
EXAMPLES::
1274
1275
sage: from sage.sets.family import EnumeratedFamily
1276
sage: f = EnumeratedFamily(Permutations(3));
1277
sage: f.__getstate__()
1278
{'enumset': Standard permutations of 3}
1279
sage: loads(dumps(f)) == f
1280
True
1281
"""
1282
return {'enumset': self.enumset}
1283
1284
def __setstate__(self, state):
1285
"""
1286
EXAMPLES::
1287
1288
sage: from sage.sets.family import EnumeratedFamily
1289
sage: f = EnumeratedFamily(Permutations(0));
1290
sage: f.__setstate__({'enumset': Permutations(3)})
1291
sage: f
1292
Family (Standard permutations of 3)
1293
"""
1294
self.__init__(state['enumset'])
1295
1296