def __init__(self, inst, f, name=None, **options): r""" Initialize ``self``. TESTS:: sage: from sage.sets.set_from_iterator import DummyExampleForPicklingTest sage: d = DummyExampleForPicklingTest() sage: d.f() {10, 11, 12, 13, 14, ...} It is possible to pickle/unpickle the class and the instance:: sage: loads(dumps(DummyExampleForPicklingTest))().f() {10, 11, 12, 13, 14, ...} sage: loads(dumps(d)).f() {10, 11, 12, 13, 14, ...} But not the enumerated set:: sage: loads(dumps(d.f())) # py2 Traceback (most recent call last): ... PicklingError: Can't pickle <... 'function'>: attribute lookup __builtin__.function failed sage: loads(dumps(d.f())) # py3 Traceback (most recent call last): ... _pickle.PicklingError: Can't pickle <function DummyExampleForPicklingTest.f at ...>: it's not the same object as sage.sets.set_from_iterator.DummyExampleForPicklingTest.f """ self.inst = inst self.f = f self.af = ArgumentFixer(self.f) if hasattr(f, "__name__"): self.__name__ = f.__name__ else: self.__name__ = f.__name__ self.__module__ = f.__module__ self.name = name self.options = options
def __init__(self, f=None, name=None, **options): r""" Initialize ``self``. TESTS:: sage: from sage.sets.set_from_iterator import set_from_function sage: F = set_from_function(category=FiniteEnumeratedSets())(xsrange) sage: TestSuite(F(100)).run() sage: TestSuite(F(1,5,2)).run() sage: TestSuite(F(0)).run() """ if f is not None: self.f = f if hasattr(f, "__name__"): self.__name__ = f.__name__ else: self.__name__ = f.__name__ self.__module__ = f.__module__ self.af = ArgumentFixer(f) if name is not None: self.name = name self.options = options
def __call__(self, f): """Return decorated version of f.""" from sage.misc.function_mangling import ArgumentFixer A = ArgumentFixer(f) def g(*args, **kwds): k = A.fix_to_named(*args, **kwds) try: return self.db[k] except KeyError: pass x = self.db[k] = f(*args, **kwds) self.db.commit() return x def keys(): return self.db.keys() g.keys = keys g.db = self.db return g
def __init__(self, inst, f, name=None, **options): r""" Initialize ``self``. TESTS:: sage: from sage.sets.set_from_iterator import DummyExampleForPicklingTest sage: d = DummyExampleForPicklingTest() sage: d.f() {10, 11, 12, 13, 14, ...} It is possible to pickle/unpickle the class and the instance:: sage: loads(dumps(DummyExampleForPicklingTest))().f() {10, 11, 12, 13, 14, ...} sage: loads(dumps(d)).f() {10, 11, 12, 13, 14, ...} But not the enumerated set:: sage: loads(dumps(d.f())) Traceback (most recent call last): ... PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed """ self.inst = inst self.f = f self.af = ArgumentFixer(self.f) if hasattr(f, "__name__"): self.__name__ = f.__name__ else: self.__name__ = f.__name__ self.__module__ = f.__module__ self.name = name self.options = options
class EnumeratedSetFromIterator_method_caller(Decorator): r""" Caller for decorated method in class. INPUT: - ``inst`` -- an instance of a class - ``f`` -- a method of a class of ``inst`` (and not of the instance itself) - ``name`` -- optional -- either a string (which may contains substitution rules from argument or a function args,kwds -> string. - ``options`` -- any option accepted by :class:`EnumeratedSetFromIterator` """ def __init__(self, inst, f, name=None, **options): r""" Initialize ``self``. TESTS:: sage: from sage.sets.set_from_iterator import DummyExampleForPicklingTest sage: d = DummyExampleForPicklingTest() sage: d.f() {10, 11, 12, 13, 14, ...} It is possible to pickle/unpickle the class and the instance:: sage: loads(dumps(DummyExampleForPicklingTest))().f() {10, 11, 12, 13, 14, ...} sage: loads(dumps(d)).f() {10, 11, 12, 13, 14, ...} But not the enumerated set:: sage: loads(dumps(d.f())) # py2 Traceback (most recent call last): ... PicklingError: Can't pickle <... 'function'>: attribute lookup __builtin__.function failed sage: loads(dumps(d.f())) # py3 Traceback (most recent call last): ... _pickle.PicklingError: Can't pickle <function DummyExampleForPicklingTest.f at ...>: it's not the same object as sage.sets.set_from_iterator.DummyExampleForPicklingTest.f """ self.inst = inst self.f = f self.af = ArgumentFixer(self.f) if hasattr(f, "__name__"): self.__name__ = f.__name__ else: self.__name__ = f.__name__ self.__module__ = f.__module__ self.name = name self.options = options def __call__(self,*args,**kwds): r""" Returns an instance of :class:`EnumeratedSetFromIterator` with proper argument. TESTS:: sage: from sage.sets.set_from_iterator import set_from_method sage: class A: ....: @set_from_method(name = lambda self,n: str(self)*n) ....: def f(self,n): ....: return xsrange(n) ....: def __repr__(self): ....: return "A" sage: a = A() sage: a.f(3) # indirect doctest AAA sage: A.f(a,3) # indirect doctest AAA sage: [x for x in a.f(6)] # indirect doctest [0, 1, 2, 3, 4, 5] """ if self.inst is not None: args = (self.inst,) + args if self.name: if isinstance(self.name,str): aa,kk = self.af.fix_to_named(*args,**kwds) name = self.name%dict(kk) else: name = self.name(*args, **kwds) return EnumeratedSetFromIterator(self.f, args, kwds, name, **self.options) return EnumeratedSetFromIterator(self.f, args, kwds, **self.options) def __get__(self, inst, cls): r""" Get a :class:`EnumeratedSetFromIterator_method_caller` bound to a specific instance of the class of the cached method. .. NOTE:: :class:`EnumeratedSetFromIterator_method_caller` has a separate ``__get__`` because of the special behavior of category framework for element classes which are not of extension type (see :meth:`sage.structure.element.Element.__get__`). TESTS:: sage: from sage.sets.set_from_iterator import set_from_method sage: class A: ....: stop = 10000 ....: @set_from_method ....: def f(self,start): ....: return xsrange(start,self.stop) sage: a = A() sage: A.f(a,4) {4, 5, 6, 7, 8, ...} sage: class B: ....: stop = 10000 ....: @set_from_method(category=FiniteEnumeratedSets()) ....: def f(self,start): ....: return xsrange(start,self.stop) sage: b = B() sage: B.f(b,2) {2, 3, 4, 5, 6, ...} """ return EnumeratedSetFromIterator_method_caller( inst, self.f, self.name, **self.options)
class EnumeratedSetFromIterator_function_decorator(Decorator): r""" Decorator for :class:`EnumeratedSetFromIterator`. Name could be string or a function ``(args,kwds) -> string``. .. WARNING:: If you are going to use this with the decorator ``cached_function``, you must place the ``cached_function`` first. See the example below. EXAMPLES:: sage: from sage.sets.set_from_iterator import set_from_function sage: @set_from_function ....: def f(n): ....: for i in range(n): ....: yield i**2 + i + 1 sage: f(3) {1, 3, 7} sage: f(100) {1, 3, 7, 13, 21, ...} To avoid ambiguity, it is always better to use it with a call which provides optional global initialization for the call to :class:`EnumeratedSetFromIterator`:: sage: @set_from_function(category=InfiniteEnumeratedSets()) ....: def Fibonacci(): ....: a = 1; b = 2 ....: while True: ....: yield a ....: a, b = b, a + b sage: F = Fibonacci() sage: F {1, 2, 3, 5, 8, ...} sage: F.cardinality() +Infinity A simple example with many options:: sage: @set_from_function( ....: name = "From %(m)d to %(n)d", ....: category = FiniteEnumeratedSets()) ....: def f(m, n): return xsrange(m,n+1) sage: E = f(3,10); E From 3 to 10 sage: E.list() [3, 4, 5, 6, 7, 8, 9, 10] sage: E = f(1,100); E From 1 to 100 sage: E.cardinality() 100 sage: f(n=100,m=1) == E True An example which mixes together ``set_from_function`` and ``cached_method``:: sage: @cached_function ....: @set_from_function( ....: name = "Graphs on %(n)d vertices", ....: category = FiniteEnumeratedSets(), ....: cache = True) ....: def Graphs(n): return graphs(n) sage: Graphs(10) Graphs on 10 vertices sage: Graphs(10).unrank(0) Graph on 10 vertices sage: Graphs(10) is Graphs(10) True The ``cached_function`` must go first:: sage: @set_from_function( ....: name = "Graphs on %(n)d vertices", ....: category = FiniteEnumeratedSets(), ....: cache = True) ....: @cached_function ....: def Graphs(n): return graphs(n) sage: Graphs(10) Graphs on 10 vertices sage: Graphs(10).unrank(0) Graph on 10 vertices sage: Graphs(10) is Graphs(10) False """ def __init__(self, f=None, name=None, **options): r""" Initialize ``self``. TESTS:: sage: from sage.sets.set_from_iterator import set_from_function sage: F = set_from_function(category=FiniteEnumeratedSets())(xsrange) sage: TestSuite(F(100)).run() sage: TestSuite(F(1,5,2)).run() sage: TestSuite(F(0)).run() """ if f is not None: self.f = f if hasattr(f, "__name__"): self.__name__ = f.__name__ else: self.__name__ = f.__name__ self.__module__ = f.__module__ self.af = ArgumentFixer(f) if name is not None: self.name = name self.options = options def __call__(self, *args, **kwds): r""" Build a new :class:`EnumeratedSet` by calling ``self.f`` with appropriate argument. If ``f`` is ``None``, then returns a new instance of :class:`EnumeratedSetFromIterator`. EXAMPLES:: sage: from sage.sets.set_from_iterator import set_from_function sage: F = set_from_function(category=FiniteEnumeratedSets())(xsrange) sage: F(3) {0, 1, 2} sage: F(end=7,start=3) {3, 4, 5, 6} sage: F(10).cardinality() 10 """ if hasattr(self, 'f'): # yet initialized if hasattr(self,'name'): if isinstance(self.name, str): if args or kwds: _, kk = self.af.fix_to_named(*args,**kwds) name = self.name % dict(kk) else: name = self.name else: name = self.name(*args, **kwds) return EnumeratedSetFromIterator(self.f, args, kwds, name=name, **self.options) return EnumeratedSetFromIterator(self.f, args, kwds, **self.options) else: # potential global options if args == (): f, = kwds.values() else: assert len(args) == 1 f = args[0] return EnumeratedSetFromIterator_function_decorator( f, name=getattr(self,'name',None), **self.options)
class EnumeratedSetFromIterator_method_caller(Decorator): r""" Caller for decorated method in class. INPUT: - ``inst`` -- an instance of a class - ``f`` -- a method of a class of ``inst`` (and not of the instance itself) - ``name`` -- optional -- either a string (which may contains substitution rules from argument or a function args,kwds -> string. - ``options`` -- any option accepted by :class:`EnumeratedSetFromIterator` """ def __init__(self, inst, f, name=None, **options): r""" Initialize ``self``. TESTS:: sage: from sage.sets.set_from_iterator import DummyExampleForPicklingTest sage: d = DummyExampleForPicklingTest() sage: d.f() {10, 11, 12, 13, 14, ...} It is possible to pickle/unpickle the class and the instance:: sage: loads(dumps(DummyExampleForPicklingTest))().f() {10, 11, 12, 13, 14, ...} sage: loads(dumps(d)).f() {10, 11, 12, 13, 14, ...} But not the enumerated set:: sage: loads(dumps(d.f())) Traceback (most recent call last): ... PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed """ self.inst = inst self.f = f self.af = ArgumentFixer(self.f) if hasattr(f, "__name__"): self.__name__ = f.__name__ else: self.__name__ = f.__name__ self.__module__ = f.__module__ self.name = name self.options = options def __call__(self,*args,**kwds): r""" Returns an instance of :class:`EnumeratedSetFromIterator` with proper argument. TESTS:: sage: from sage.sets.set_from_iterator import set_from_method sage: class A: ... @set_from_method(name = lambda self,n: str(self)*n) ... def f(self,n): ... return xsrange(n) ... def __repr__(self): ... return "A" sage: a = A() sage: a.f(3) # indirect doctest AAA sage: A.f(a,3) # indirect doctest AAA sage: [x for x in a.f(6)] # indirect doctest [0, 1, 2, 3, 4, 5] """ if self.inst is not None: args = (self.inst,) + args if self.name: if isinstance(self.name,str): aa,kk = self.af.fix_to_named(*args,**kwds) name = self.name%dict(kk) else: name = self.name(*args, **kwds) return EnumeratedSetFromIterator(self.f, args, kwds, name, **self.options) return EnumeratedSetFromIterator(self.f, args, kwds, **self.options) def __get__(self, inst, cls): r""" Get a :class:`EnumeratedSetFromIterator_method_caller` bound to a specific instance of the class of the cached method. .. NOTE:: :class:`EnumeratedSetFromIterator_method_caller` has a separate ``__get__`` because of the special behavior of category framework for element classes which are not of extension type (see :meth:`sage.structure.element.Element.__get__`). TESTS:: sage: from sage.sets.set_from_iterator import set_from_method sage: class A: ....: stop = 10000 ....: @set_from_method ....: def f(self,start): ....: return xsrange(start,self.stop) sage: a = A() sage: A.f(a,4) {4, 5, 6, 7, 8, ...} sage: class B: ....: stop = 10000 ....: @set_from_method(category=FiniteEnumeratedSets()) ....: def f(self,start): ....: return xsrange(start,self.stop) sage: b = B() sage: B.f(b,2) {2, 3, 4, 5, 6, ...} """ return EnumeratedSetFromIterator_method_caller( inst, self.f, self.name, **self.options)
class EnumeratedSetFromIterator_function_decorator(Decorator): r""" Decorator for :class:`EnumeratedSetFromIterator`. Name could be string or a function ``(args,kwds) -> string``. .. WARNING:: If you are going to use this with the decorator ``cached_function``, you must place the ``cached_function`` first. See the example below. EXAMPLES:: sage: from sage.sets.set_from_iterator import set_from_function sage: @set_from_function ... def f(n): ... for i in xrange(n): ... yield i**2 + i + 1 sage: f(3) {1, 3, 7} sage: f(100) {1, 3, 7, 13, 21, ...} To avoid ambiguity, it is always better to use it with a call which provides optional global initialization for the call to :class:`EnumeratedSetFromIterator`:: sage: @set_from_function(category=InfiniteEnumeratedSets()) ... def Fibonacci(): ... a = 1; b = 2 ... while True: ... yield a ... a,b = b,a+b sage: F = Fibonacci() sage: F {1, 2, 3, 5, 8, ...} sage: F.cardinality() +Infinity A simple example with many options:: sage: @set_from_function( ... name = "From %(m)d to %(n)d", ... category = FiniteEnumeratedSets()) ... def f(m,n): return xsrange(m,n+1) sage: E = f(3,10); E From 3 to 10 sage: E.list() [3, 4, 5, 6, 7, 8, 9, 10] sage: E = f(1,100); E From 1 to 100 sage: E.cardinality() 100 sage: f(n=100,m=1) == E True An example which mixes together ``set_from_function`` and ``cached_method``:: sage: @cached_function ... @set_from_function( ... name = "Graphs on %(n)d vertices", ... category = FiniteEnumeratedSets(), ... cache = True) ... def Graphs(n): return graphs(n) sage: Graphs(10) Graphs on 10 vertices sage: Graphs(10).unrank(0) Graph on 10 vertices sage: Graphs(10) is Graphs(10) True The ``cached_function`` must go first:: sage: @set_from_function( ... name = "Graphs on %(n)d vertices", ... category = FiniteEnumeratedSets(), ... cache = True) ... @cached_function ... def Graphs(n): return graphs(n) sage: Graphs(10) Graphs on 10 vertices sage: Graphs(10).unrank(0) Graph on 10 vertices sage: Graphs(10) is Graphs(10) False """ def __init__(self, f=None, name=None, **options): r""" Initialize ``self``. TESTS:: sage: from sage.sets.set_from_iterator import set_from_function sage: F = set_from_function(category=FiniteEnumeratedSets())(xsrange) sage: TestSuite(F(100)).run() sage: TestSuite(F(1,5,2)).run() sage: TestSuite(F(0)).run() """ if f is not None: self.f = f if hasattr(f, "__name__"): self.__name__ = f.__name__ else: self.__name__ = f.__name__ self.__module__ = f.__module__ self.af = ArgumentFixer(f) if name is not None: self.name = name self.options = options def __call__(self, *args, **kwds): r""" Build a new :class:`EnumeratedSet` by calling ``self.f`` with apropriate argument. If ``f`` is ``None``, then returns a new instance of :class:`EnumeratedSetFromIterator`. EXAMPLES:: sage: from sage.sets.set_from_iterator import set_from_function sage: F = set_from_function(category=FiniteEnumeratedSets())(xsrange) sage: F(3) {0, 1, 2} sage: F(end=7,start=3) {3, 4, 5, 6} sage: F(10).cardinality() 10 """ options = self.options if hasattr(self, 'f'): # yet initialized if hasattr(self,'name'): if isinstance(self.name,str): if args or kwds: _,kk = self.af.fix_to_named(*args,**kwds) name = self.name%dict(kk) else: name = self.name else: name = self.name(*args,**kwds) return EnumeratedSetFromIterator(self.f, args, kwds, name=name, **self.options) return EnumeratedSetFromIterator(self.f, args, kwds, **self.options) else: # potential global options if args == (): assert len(kwds.keys()) == 1 f = kwds.values()[0] else: assert len(args) == 1 f = args[0] return EnumeratedSetFromIterator_function_decorator( f, name=getattr(self,'name',None), **self.options)