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