Ticket #3661: trac_36612.patch
File trac_36612.patch, 12.1 KB (added by , 11 years ago) 


sage/combinat/family.py
# HG changeset patch # User Mike Hansen <mhansen@gmail.com> # Date 1216181237 18000 # Node ID 770d745eca589b9bc5877206b9a4b2325a34ed41 # Parent b870354dc81bb12bca773c0cf302ba8a1678792b Added doctests and improved pickling functionality for families. diff r b870354dc81b r 770d745eca58 sage/combinat/family.py
a b 1 """ 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 #***************************************************************************** 1 19 from sage.combinat.combinat import CombinatorialClass 2 20 from sage.combinat.finite_class import FiniteCombinatorialClass_l 3 21 … … 41 59 ['a', 'b', 'd'] 42 60 sage: f.keys() 43 61 [3, 4, 7] 44 sage: 'b' in f # todo: not implemented62 sage: 'b' in f 45 63 True 46 sage: 'e' in f # todo: not implemented64 sage: 'e' in f 47 65 False 48 66 49 67 A familly can also be constructed by its index set $I$ and a … … 69 87 list to be hashable. One can ask instead for the images $f(i)$ 70 88 to be computed lazily, when needed: 71 89 72 sage: f = LazyFamily([3,4,7], lambda i: 2 *i)90 sage: f = LazyFamily([3,4,7], lambda i: 2r*i) 73 91 sage: f 74 92 Lazy family (f(i))_{i in [3, 4, 7]} 75 93 sage: f[7] … … 82 100 3 83 101 84 102 This allows in particular for modeling infinite families: 85 sage: f = Family(ZZ, lambda i: 2 *i)103 sage: f = Family(ZZ, lambda i: 2r*i) 86 104 sage: f 87 105 Lazy family (f(i))_{i in Integer Ring} 88 106 sage: f.keys() … … 95 113 sage: i.next(), i.next(), i.next(), i.next(), i.next() 96 114 (0, 2, 2, 4, 4) 97 115 98 Caveat: families with lazy behavior cannot be pickled 99 116 Caveat: Only certain families with lazy behavior can be pickled. In 117 particular, only functions that work with Sage's pickle_function 118 and unpickle_function (in sage.misc.fpickle) will correctly 119 unpickle. 100 120 101 121 Finally, it can occasionally be useful to add some hidden 102 elements in a famil ly, which are accessible as f[i], but122 elements in a family, which are accessible as f[i], but 103 123 do not appear in the keys or the container operations. 104 124 105 125 sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2]) … … 226 246 raise NotImplementedError 227 247 228 248 class AbstractFamily(CombinatorialClass): 229 230 249 def hidden_keys(self): 231 250 """ 232 Returns the hidden keys of the family, if any 251 Returns the hidden keys of the family, if any. 252 253 EXAMPLES: 254 sage: f = Family({3: 'a', 4: 'b', 7: 'd'}) 255 sage: f.hidden_keys() 256 [] 233 257 """ 234 258 return [] 235 259 … … 293 317 ['a', 'b', 'd'] 294 318 sage: [ x for x in f ] 295 319 ['a', 'b', 'd'] 296 sage: f == loads(dumps(f))297 True298 320 """ 299 321 300 322 def __init__(self, dictionary, keys = None): 323 """ 324 TESTS: 325 sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'}) 326 sage: f == loads(dumps(f)) 327 True 328 """ 301 329 # TODO: use keys to specify the order of the elements 302 330 self.dictionary = dictionary 303 331 self.keys = dictionary.keys 304 self.__iter__ = dictionary.itervalues305 self.list = dictionary.values # should not be required306 332 self.values = dictionary.values 307 self.__getitem__ = dictionary.__getitem__308 333 309 334 def __repr__(self): 335 """ 336 EXAMPLES: 337 sage: FiniteFamily({3: 'a'}) 338 Finite family {3: 'a'} 339 """ 310 340 return "Finite family %s"%self.dictionary 311 341 342 def __contains__(self, x): 343 """ 344 EXAMPLES: 345 sage: f = FiniteFamily({3: 'a'}) 346 sage: 'a' in f 347 True 348 sage: 'b' in f 349 False 350 """ 351 return x in self.values() 352 312 353 def count(self): 354 """ 355 Returns the number of elements in self. 356 357 EXAMPLES: 358 sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'}) 359 sage: f.count() 360 3 361 """ 313 362 return len(self.dictionary) 314 363 315 # Why isn't it sufficient to set self.__getitem__ as above? 364 def iterator(self): 365 """ 366 EXAMPLES: 367 sage: f = FiniteFamily({3: 'a'}) 368 sage: i = iter(f) 369 sage: i.next() 370 'a' 371 372 """ 373 return iter(self.values()) 374 316 375 def __getitem__(self, i): 317 return self.__getitem__(i) 376 """ 377 378 Note that we can't just do self.__getitem__ = dictionary.__getitem__ in the 379 __init__ method since Python queries the object's type/class 380 for the special methods rather than querying the object itself. 381 382 EXAMPLES: 383 sage: f = FiniteFamily({3: 'a', 4: 'b', 7: 'd'}) 384 sage: f[3] 385 'a' 386 """ 387 return self.dictionary.__getitem__(i) 318 388 319 389 # For the pickle and copy modules 320 390 def __getstate__(self): 391 """ 392 TESTS: 393 sage: f = FiniteFamily({3: 'a'}) 394 sage: f.__getstate__() 395 {'dictionary': {3: 'a'}} 396 """ 321 397 return {'dictionary': self.dictionary} 322 398 323 399 def __setstate__(self, state): 400 """ 401 EXAMPLES: 402 sage: f = FiniteFamily({3: 'a'}) 403 sage: f.__setstate__({'dictionary': {4:'b'}}) 404 sage: f 405 Finite family {4: 'b'} 406 407 """ 324 408 self.__init__(state['dictionary']) 325 409 326 410 class FiniteFamilyWithHiddenKeys(FiniteFamily): … … 330 414 remembered). Instances should be created via the Family factory, 331 415 which see for examples and tests. 332 416 333 Caveat: instances of this class cannot be pickled, because the334 hidden_function itself cannot.417 Caveat: Only instances of this class whose functions are 418 compatible with sage.misc.fpickle can be pickled. 335 419 """ 336 420 def __init__(self, dictionary, hidden_keys, hidden_function): 421 """ 422 EXAMPLES: 423 sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2]) 424 sage: f == loads(dumps(f)) 425 True 426 """ 337 427 FiniteFamily.__init__(self, dictionary) 338 428 self._hidden_keys = hidden_keys 339 429 self.hidden_function = hidden_function … … 344 434 #self.__getitem__ = lambda i: dictionary[i] if dictionary.has_key(i) else hidden_dictionary[i] 345 435 346 436 def __getitem__(self, i): 347 if self.dictionary.has_key(i): 437 """ 438 EXAMPLES: 439 sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2]) 440 sage: f[3] 441 6 442 sage: f[2] 443 4 444 sage: f[5] 445 Traceback (most recent call last): 446 ... 447 KeyError 448 449 """ 450 if i in self.dictionary: 348 451 return self.dictionary[i] 349 if not self.hidden_dictionary.has_key(i): 350 if not i in self._hidden_keys: 452 453 if i not in self.hidden_dictionary: 454 if i not in self._hidden_keys: 351 455 raise KeyError 352 456 self.hidden_dictionary[i] = self.hidden_function(i) 457 353 458 return self.hidden_dictionary[i] 354 459 355 460 def hidden_keys(self): 461 """ 462 Returns self's hidden keys. 463 464 EXAMPLES: 465 sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2]) 466 sage: f.hidden_keys() 467 [2] 468 """ 356 469 return self._hidden_keys 357 470 358 471 def __getstate__(self): 359 raise NotImplementedError 472 """ 473 EXAMPLES: 474 sage: f = Family([3,4,7], lambda i: 2*i, hidden_keys=[2]) 475 sage: d = f.__getstate__() 476 sage: d['hidden_keys'] 477 [2] 478 """ 479 from sage.misc.fpickle import pickle_function 480 f = pickle_function(self.hidden_function) 481 return {'dictionary': self.dictionary, 482 'hidden_keys': self._hidden_keys, 483 'hidden_dictionary': self.hidden_dictionary, 484 'hidden_function': f} 485 486 def __setstate__(self, d): 487 """ 488 EXAMPLES: 489 sage: f = Family([3,4,7], lambda i: 2r*i, hidden_keys=[2]) 490 sage: d = f.__getstate__() 491 sage: f = Family([4,5,6], lambda i: 2r*i, hidden_keys=[2]) 492 sage: f.__setstate__(d) 493 sage: f.keys() 494 [3, 4, 7] 495 sage: f[3] 496 6 497 """ 498 from sage.misc.fpickle import unpickle_function 499 hidden_function = unpickle_function(d['hidden_function']) 500 self.__init__(d['dictionary'], d['hidden_keys'], hidden_function) 501 self.hidden_dictionary = d['hidden_dictionary'] 502 360 503 361 504 class LazyFamily(AbstractFamily): 362 505 r""" … … 366 509 Instances should be created via the Family factory, which see for 367 510 examples and tests. 368 511 """ 369 370 512 def __init__(self, set, function, name = "f"): 513 """ 514 EXAMPLES: 515 sage: f = LazyFamily([3,4,7], lambda i: 2r*i); f 516 Lazy family (f(i))_{i in [3, 4, 7]} 517 sage: f == loads(dumps(f)) 518 True 519 """ 371 520 self.set = set 372 521 self.name = name 373 self. __getitem__= function522 self.function = function 374 523 375 524 def __repr__(self): 525 """ 526 EXAMPLES: 527 sage: f = LazyFamily([3,4,7], lambda i: 2*i); f 528 Lazy family (f(i))_{i in [3, 4, 7]} 529 """ 376 530 return "Lazy family (%s(i))_{i in %s}"%(self.name,self.set) 377 531 378 532 def keys(self): 533 """ 534 Returns self's keys. 535 536 EXAMPLES: 537 sage: f = LazyFamily([3,4,7], lambda i: 2*i) 538 sage: f.keys() 539 [3, 4, 7] 540 """ 379 541 return self.set 380 542 381 def __iter__(self): 382 for i in self.set.__iter__(): 543 def iterator(self): 544 """ 545 EXAMPLES: 546 sage: f = LazyFamily([3,4,7], lambda i: 2*i) 547 sage: [i for i in f] 548 [6, 8, 14] 549 """ 550 for i in self.set: 383 551 yield self[i] 384 552 385 # Should disappear 386 iterator = __iter__ 553 def __getitem__(self, i): 554 """ 555 EXAMPLES: 556 sage: f = LazyFamily([3,4,7], lambda i: 2*i) 557 sage: f[3] 558 6 559 560 TESTS: 561 sage: f[5] 562 10 563 """ 564 return self.function(i) 387 565 388 # Why isn't it sufficient to set self.__getitem__ as above? 389 def __getitem__(self, i): 390 return self.__getitem__(i) 566 def __getstate__(self): 567 """ 568 EXAMPLES: 569 sage: f = LazyFamily([3,4,7], lambda i: 2r*i) 570 sage: d = f.__getstate__() 571 sage: d['set'] 572 [3, 4, 7] 573 574 """ 575 from sage.misc.fpickle import pickle_function 576 f = pickle_function(self.function) 577 return {'set': self.set, 578 'name': self.name, 579 'function': f} 580 581 def __setstate__(self, d): 582 """ 583 EXAMPLES: 584 sage: f = LazyFamily([3,4,7], lambda i: 2r*i) 585 sage: d = f.__getstate__() 586 sage: f = LazyFamily([4,5,6], lambda i: 2r*i) 587 sage: f.__setstate__(d) 588 sage: f.keys() 589 [3, 4, 7] 590 sage: f[3] 591 6 592 """ 593 from sage.misc.fpickle import unpickle_function 594 function = unpickle_function(d['function']) 595 self.__init__(d['set'], function, d['name'])