Ticket #15349: trac_15349-lazy-family-values-dg.patch
File trac_15349-lazy-family-values-dg.patch, 16.3 KB (added by , 9 years ago) |
---|
-
sage/sets/family.py
# HG changeset patch # User darij grinberg <darijgrinberg@gmail.com> # Date 1383462578 25200 # Node ID 839c49fe7d4c206d35358dd201f335b8e3885801 # Parent dc029471c9063cc44bc9aa05ffa40b9ca97da8c1 trac #15349: value() for lazy families diff --git a/sage/sets/family.py b/sage/sets/family.py
a b from sage.categories.enumerated_sets imp 37 37 from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets 38 38 from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets 39 39 from sage.sets.finite_enumerated_set import FiniteEnumeratedSet 40 from sage.misc.lazy_import import lazy_import41 40 from sage.rings.integer import Integer 42 41 from sage.misc.misc import AttrCallObject 43 from warnings import warn44 name_warn_message = "The keyword name for family has never been used and will be removed shortly. Please update your code."45 42 46 def Family(indices, function = None, hidden_keys = [], hidden_function = None, lazy = False , name=None):43 def Family(indices, function = None, hidden_keys = [], hidden_function = None, lazy = False): 47 44 r""" 48 A Familyis an associative container which models a family49 `(f_i)_{i \in I}`. Then, f[i]returns the element of the family50 indexed by i. Whenever available, set and combinatorial class51 operations (counting, iteration, listing) on the family are induced52 from those of the index set.45 A ``Family`` is an associative container which models a family 46 `(f_i)_{i \in I}`. Then, ``f[i]`` returns the element of the family 47 ``f`` indexed by ``i``. Whenever available, set and combinatorial 48 class operations (counting, iteration, listing) on the family are 49 induced from those of the index set. 53 50 54 51 There are several available implementations (classes) for different 55 usages; Family serves as a factory, and will create instances of56 the appropriate classes depending on its arguments.52 usages; ``Family`` serves as a factory, and will create instances 53 of the appropriate classes depending on its arguments. 57 54 58 55 EXAMPLES: 59 56 60 In its simplest form, a list l or a tuple by itself is considered as the61 family `(l[i]_{i \in I})` where `I` is the range `0\dots,len(l)`. So62 Family(l) returns the corresponding family::57 In its simplest form, a list ``l`` or a tuple by itself is considered 58 as the family `(l[i]_{i \in I})` where `I` is the range 59 `0,1,\dots,len(l)-1`. So Family(l) returns the corresponding family:: 63 60 64 61 sage: f = Family([1,2,3]) 65 62 sage: f … … def Family(indices, function = None, hid 74 71 sage: f 75 72 Family (3, 5, 7) 76 73 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':: 74 A family can also be constructed from a dictionary ``t``. The resulting 75 family is very close to ``t``, except that the elements of the family 76 are the values of ``t``. Here, we define the family 77 `(f_i)_{i \in \{3,4,7\}}` with ``f_3='a'``, ``f_4='b'``, and 78 ``f_7='d'``:: 81 79 82 80 sage: f = Family({3: 'a', 4: 'b', 7: 'd'}) 83 81 sage: f … … def Family(indices, function = None, hid 152 150 153 151 Note that the ``lazy`` keyword parameter is only needed to force 154 152 laziness. Usually it is automatically set to a correct default value (ie: 155 ``False`` for finite data structures and ``True`` for enumerated sets ::153 ``False`` for finite data structures and ``True`` for enumerated sets):: 156 154 157 155 sage: f == Family(ZZ, lambda i: 2*i) 158 156 True 159 157 160 Beware that for those kind of families len(f)is not supposed to161 work. As a replacement, use the .cardinality()method::158 Beware that for those kinds of families ``len(f)`` is not supposed to 159 work. As a replacement, use the ``.cardinality()`` method:: 162 160 163 161 sage: f = Family(Permutations(3), attrcall("to_lehmer_code")) 164 162 sage: list(f) … … def Family(indices, function = None, hid 167 165 6 168 166 169 167 Caveat: Only certain families with lazy behavior can be pickled. In 170 particular, only functions that work with Sage's pickle_function171 and unpickle_function (in sage.misc.fpickle) will correctly168 particular, only functions that work with Sage's ``pickle_function`` 169 and ``unpickle_function`` (in ``sage.misc.fpickle``) will correctly 172 170 unpickle. The following two work:: 173 171 174 172 sage: f = Family(Permutations(3), lambda p: p.to_lehmer_code()); f … … def Family(indices, function = None, hid 192 190 ValueError: Cannot pickle code objects from closures 193 191 194 192 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 the196 keys or the container operations::193 to a family, which are accessible as ``f[i]``, but do not appear in 194 the keys or the container operations:: 197 195 198 196 sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2]) 199 197 sage: f … … def Family(indices, function = None, hid 217 215 called:: 218 216 219 217 sage: def compute_value(i): 220 ... print('computing 2*'+str(i))221 ... return 2*i218 ....: print('computing 2*'+str(i)) 219 ....: return 2*i 222 220 sage: f = Family([3,4,7], compute_value, hidden_keys=[2]) 223 221 computing 2*3 224 222 computing 2*4 … … def Family(indices, function = None, hid 264 262 sage: len(f) 265 263 3 266 264 267 Family accept finite and infinite EnumeratedSets as input::265 ``Family`` accepts finite and infinite ``EnumeratedSet``s as input:: 268 266 269 267 sage: f = Family(FiniteEnumeratedSet([1,2,3])) 270 268 sage: f … … def Family(indices, function = None, hid 344 342 ['cc', 'aa', 'bb'] 345 343 """ 346 344 347 if name is not None:348 warn(name_warn_message)349 345 assert(type(hidden_keys) == list) 350 346 assert(isinstance(lazy, bool)) 351 347 352 348 if hidden_keys == []: 353 349 if hidden_function is not None: 354 raise ValueError , "hidden_function keyword only makes sense together with hidden_keys keyword !"350 raise ValueError("hidden_function keyword only makes sense together with hidden_keys keyword !") 355 351 elif function is None: 356 352 if lazy: 357 raise ValueError , "lazy keyword only makes sense together with function keyword !"353 raise ValueError("lazy keyword only makes sense together with function keyword !") 358 354 if isinstance(indices, dict): 359 355 return FiniteFamily(indices) 360 356 if isinstance(indices, (list, tuple) ): … … def Family(indices, function = None, hid 375 371 return LazyFamily(indices, function) 376 372 else: 377 373 if lazy: 378 raise ValueError , "lazy keyword is incompatible with hidden keys !"374 raise ValueError("lazy keyword is incompatible with hidden keys !") 379 375 if hidden_function is None: 380 376 hidden_function = function 381 377 return FiniteFamilyWithHiddenKeys(dict([(i, function(i)) for i in indices]), … … def Family(indices, function = None, hid 385 381 386 382 class AbstractFamily(Parent): 387 383 """ 388 The abstract class for family 384 The abstract class for family. 389 385 390 386 Any family belongs to a class which inherits from ``AbstractFamily``. 391 387 """ … … class AbstractFamily(Parent): 401 397 """ 402 398 return [] 403 399 404 def zip(self, f, other , name = None):400 def zip(self, f, other): 405 401 """ 406 402 Given two families with same index set `I` (and same hidden 407 403 keys if relevant), returns the family … … class AbstractFamily(Parent): 419 415 """ 420 416 assert(self.keys() == other.keys()) 421 417 assert(self.hidden_keys() == other.hidden_keys()) 422 if name is not None:423 warn(name_warn_message)424 418 return Family(self.keys(), lambda i: f(self[i],other[i]), hidden_keys = self.hidden_keys()) 425 419 426 def map(self, f , name = None):420 def map(self, f): 427 421 """ 428 422 Returns the family `( f(\mathtt{self}[i]) )_{i \in I}`, where 429 423 `I` is the index set of self. … … class AbstractFamily(Parent): 437 431 sage: list(g) 438 432 ['a1', 'b1', 'd1'] 439 433 """ 440 if name is not None:441 warn(name_warn_message)442 434 return Family(self.keys(), lambda i: f(self[i]), hidden_keys = self.hidden_keys()) 443 435 444 436 # temporary; tested by TestSuite. … … class AbstractFamily(Parent): 466 458 467 459 class FiniteFamily(AbstractFamily): 468 460 r""" 469 A FiniteFamily is an associative container which models a finite470 f amily `(f_i)_{i \in I}`. Its elements `f_i` are therefore471 its values. Instances should be created via the Familyfactory,472 which s eefor further examples and tests.461 A ``FiniteFamily`` is an associative container which models a 462 finite family `(f_i)_{i \in I}`. Its elements `f_i` are therefore 463 its values. Instances should be created via the ``Family`` factory, 464 which should be consulted for further examples and tests. 473 465 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:: 466 EXAMPLES: 467 468 We define the family `(f_i)_{i \in \{3,4,7\}}` with ``f_3='a'``, 469 ``f_4='b'``, and ``f_7='d'``:: 476 470 477 471 sage: from sage.sets.family import FiniteFamily 478 472 sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'}) … … class FiniteFamily(AbstractFamily): 489 483 sage: f.keys() 490 484 [3, 4, 7] 491 485 492 However fbehaves as a container for the `f_i`'s::486 However ``f`` behaves as a container for the `f_i`'s:: 493 487 494 488 sage: list(f) 495 489 ['a', 'b', 'd'] … … class FiniteFamily(AbstractFamily): 543 537 544 538 def values(self): 545 539 """ 546 Return s the elements of this family540 Return the list of the elements of this family. 547 541 548 542 EXAMPLES:: 549 543 … … class FiniteFamily(AbstractFamily): 697 691 698 692 class FiniteFamilyWithHiddenKeys(FiniteFamily): 699 693 r""" 700 A close variant of FiniteFamilywhere the family contains some694 A close variant of ``FiniteFamily`` where the family contains some 701 695 hidden keys whose corresponding values are computed lazily (and 702 remembered). Instances should be created via the Family factory,703 which seefor examples and tests.696 remembered). Instances should be created via the ``Family`` 697 factory, which should also be consulted for examples and tests. 704 698 705 699 Caveat: Only instances of this class whose functions are compatible 706 with sage.misc.fpicklecan be pickled.700 with `sage.misc.fpickle`` can be pickled. 707 701 """ 708 702 def __init__(self, dictionary, hidden_keys, hidden_function): 709 703 """ … … class FiniteFamilyWithHiddenKeys(FiniteF 797 791 798 792 class LazyFamily(AbstractFamily): 799 793 r""" 800 A LazyFamily(I, f)is an associative container which models the794 ``LazyFamily(I, f)`` is an associative container which models the 801 795 (possibly infinite) family `(f(i))_{i \in I}`. 802 796 803 Instances should be created via the Family factory, which see for804 examples and tests.797 Instances should be created via the ``Family`` factory, whose 798 documentation also provides examples and tests. 805 799 """ 806 def __init__(self, set, function , name=None):800 def __init__(self, set, function): 807 801 """ 808 802 TESTS:: 809 803 … … class LazyFamily(AbstractFamily): 834 828 category = EnumeratedSets() 835 829 836 830 Parent.__init__(self, category = category) 837 if name is not None:838 warn(name_warn_message)839 831 from copy import copy 840 832 self.set = copy(set) 841 833 self.function = function … … class LazyFamily(AbstractFamily): 843 835 844 836 def __eq__(self, other): 845 837 """ 846 WARNING: Since there is no way to compare function , we only compare847 their name .838 WARNING: Since there is no way to compare functions, we only compare 839 their names. 848 840 849 841 TESTS:: 850 842 … … class LazyFamily(AbstractFamily): 855 847 sage: f == g 856 848 True 857 849 """ 858 from sage.misc.fpickle import pickle_function859 850 if not isinstance(other, self.__class__): 860 851 return False 861 852 if not self.set == other.set: … … class LazyFamily(AbstractFamily): 897 888 898 889 def keys(self): 899 890 """ 900 Returns self's keys.891 Returns ``self``'s keys. 901 892 902 893 EXAMPLES:: 903 894 … … class LazyFamily(AbstractFamily): 908 899 """ 909 900 return self.set 910 901 902 def values(self, lazy_list=False): 903 """ 904 Return the elements of this family, either as a list 905 (if the optional keyword ``lazy_list`` is set to 906 ``False``, which it is by default), or as a lazy list 907 (if that keyword is set to ``True``). 908 909 This will misbehave when ``self`` is infinite, unless 910 the optional keyword ``lazy_list`` is set to ``True``, 911 in which case a lazy list will be returned. 912 913 EXAMPLES:: 914 915 sage: from sage.sets.family import LazyFamily 916 sage: f = LazyFamily(["c", "a", "b"], lambda x: x+x) 917 sage: f.values() 918 ['cc', 'aa', 'bb'] 919 sage: f.values(lazy_list=True) 920 lazy list ['cc', 'aa', 'bb'] 921 922 sage: from itertools import count 923 sage: f = LazyFamily(count(), lambda x: x**2) 924 sage: f.values(lazy_list=True) 925 lazy list [0, 1, 4, ...] 926 """ 927 if not lazy_list: 928 return [ self.function(key) for key in self.set ] 929 else: 930 from sage.misc.lazy_list import lazy_list 931 return lazy_list( self.function(key) for key in self.set ) 932 911 933 def cardinality(self): 912 934 """ 913 Return the number of elements in self.935 Return the number of elements in ``self``. 914 936 915 937 EXAMPLES:: 916 938 … … class LazyFamily(AbstractFamily): 1009 1031 1010 1032 class TrivialFamily(AbstractFamily): 1011 1033 r""" 1012 ``TrivialFamily(c)`` turn the container cinto a family indexed by1013 the set ` {0, \dots, len(c)}`. The container `c` can be either a list or a1014 tuple.1034 ``TrivialFamily(c)`` turns the container ``c`` into a family indexed by 1035 the set `\{0, 1, \dots, \mathrm{len}(c) - 1\}`. The container `c` can 1036 be either a list or a tuple. 1015 1037 1016 Instances should be created via the Family factory, which see for1017 examples and tests.1038 Instances should be created via the ``Family`` factory, which should 1039 also be consulted for examples and tests. 1018 1040 """ 1019 1041 def __init__(self, enumeration): 1020 1042 """ … … class TrivialFamily(AbstractFamily): 1025 1047 Family (3, 4, 7) 1026 1048 sage: f = TrivialFamily([3,4,7]); f 1027 1049 Family (3, 4, 7) 1050 sage: TrivialFamily([3,4,7])[2] 1051 7 1028 1052 sage: TestSuite(f).run() 1029 1053 """ 1030 1054 Parent.__init__(self, category = FiniteEnumeratedSets()) … … class TrivialFamily(AbstractFamily): 1054 1078 1055 1079 def keys(self): 1056 1080 """ 1057 Returns self's keys.1081 Returns ``self``'s keys. 1058 1082 1059 1083 EXAMPLES:: 1060 1084 … … class TrivialFamily(AbstractFamily): 1067 1091 1068 1092 def cardinality(self): 1069 1093 """ 1070 Return the number of elements in self.1094 Return the number of elements in ``self``. 1071 1095 1072 1096 EXAMPLES:: 1073 1097 … … from sage.rings.infinity import Infinity 1143 1167 1144 1168 class EnumeratedFamily(LazyFamily): 1145 1169 r""" 1146 ``EnumeratedFamily(c)`` turn the enumerated set c into a family indexed by1147 the set `{0,\dots, c.cardinality()}`.1170 ``EnumeratedFamily(c)`` turns the enumerated set `c` into a family 1171 indexed by the set `\{0, 1, \dots, c.\mathrm{cardinality()}-1 \}`. 1148 1172 1149 Instances should be created via the Family factory, which see for1150 examples and tests.1173 Instances should be created via the ``Family`` factory; see the 1174 latter's documentation for examples and tests. 1151 1175 """ 1152 1176 def __init__(self, enumset): 1153 1177 """ … … class EnumeratedFamily(LazyFamily): 1211 1235 1212 1236 def keys(self): 1213 1237 """ 1214 Returns self's keys.1238 Returns ``self``'s keys. 1215 1239 1216 1240 EXAMPLES:: 1217 1241 … … class EnumeratedFamily(LazyFamily): 1229 1253 1230 1254 def cardinality(self): 1231 1255 """ 1232 Return the number of elements in self.1256 Return the number of elements in ``self``. 1233 1257 1234 1258 EXAMPLES:: 1235 1259