Enumerated set from iterator#

EXAMPLES:

We build a set from the iterator graphs that returns a canonical representative for each isomorphism class of graphs:

sage: # needs sage.graphs
sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator
sage: E = EnumeratedSetFromIterator(
....:   graphs,
....:   name="Graphs",
....:   category=InfiniteEnumeratedSets(),
....:   cache=True)
sage: E
Graphs
sage: E.unrank(0)
Graph on 0 vertices
sage: E.unrank(4)
Graph on 3 vertices
sage: E.cardinality()
+Infinity
sage: E.category()
Category of facade infinite enumerated sets
>>> from sage.all import *
>>> # needs sage.graphs
>>> from sage.sets.set_from_iterator import EnumeratedSetFromIterator
>>> E = EnumeratedSetFromIterator(
...   graphs,
...   name="Graphs",
...   category=InfiniteEnumeratedSets(),
...   cache=True)
>>> E
Graphs
>>> E.unrank(Integer(0))
Graph on 0 vertices
>>> E.unrank(Integer(4))
Graph on 3 vertices
>>> E.cardinality()
+Infinity
>>> E.category()
Category of facade infinite enumerated sets

The module also provides decorator for functions and methods:

sage: from sage.sets.set_from_iterator import set_from_function
sage: @set_from_function
....: def f(n): return xsrange(n)
sage: f(3)
{0, 1, 2}
sage: f(5)
{0, 1, 2, 3, 4}
sage: f(100)
{0, 1, 2, 3, 4, ...}

sage: from sage.sets.set_from_iterator import set_from_method
sage: class A:
....:     @set_from_method
....:     def f(self,n):
....:         return xsrange(n)
sage: a = A()
sage: a.f(3)
{0, 1, 2}
sage: f(100)
{0, 1, 2, 3, 4, ...}
>>> from sage.all import *
>>> from sage.sets.set_from_iterator import set_from_function
>>> @set_from_function
... def f(n): return xsrange(n)
>>> f(Integer(3))
{0, 1, 2}
>>> f(Integer(5))
{0, 1, 2, 3, 4}
>>> f(Integer(100))
{0, 1, 2, 3, 4, ...}

>>> from sage.sets.set_from_iterator import set_from_method
>>> class A:
...     @set_from_method
...     def f(self,n):
...         return xsrange(n)
>>> a = A()
>>> a.f(Integer(3))
{0, 1, 2}
>>> f(Integer(100))
{0, 1, 2, 3, 4, ...}
class sage.sets.set_from_iterator.Decorator[source]#

Bases: object

Abstract class that manage documentation and sources of the wrapped object.

The method needs to be stored in the attribute self.f

class sage.sets.set_from_iterator.DummyExampleForPicklingTest[source]#

Bases: object

Class example to test pickling with the decorator set_from_method.

Warning

This class is intended to be used in doctest only.

EXAMPLES:

sage: from sage.sets.set_from_iterator import DummyExampleForPicklingTest
sage: DummyExampleForPicklingTest().f()
{10, 11, 12, 13, 14, ...}
>>> from sage.all import *
>>> from sage.sets.set_from_iterator import DummyExampleForPicklingTest
>>> DummyExampleForPicklingTest().f()
{10, 11, 12, 13, 14, ...}
f()[source]#

Returns the set between self.start and self.stop.

EXAMPLES:

sage: from sage.sets.set_from_iterator import DummyExampleForPicklingTest
sage: d = DummyExampleForPicklingTest()
sage: d.f()
{10, 11, 12, 13, 14, ...}
sage: d.start = 4
sage: d.stop = 200
sage: d.f()
{4, 5, 6, 7, 8, ...}
>>> from sage.all import *
>>> from sage.sets.set_from_iterator import DummyExampleForPicklingTest
>>> d = DummyExampleForPicklingTest()
>>> d.f()
{10, 11, 12, 13, 14, ...}
>>> d.start = Integer(4)
>>> d.stop = Integer(200)
>>> d.f()
{4, 5, 6, 7, 8, ...}
start = 10#
stop = 100#
class sage.sets.set_from_iterator.EnumeratedSetFromIterator(f, args=None, kwds=None, name=None, category=None, cache=False)[source]#

Bases: Parent

A class for enumerated set built from an iterator.

INPUT:

  • f – a function that returns an iterable from which the set is built from

  • args – tuple – arguments to be sent to the function f

  • kwds – dictionary – keywords to be sent to the function f

  • name – an optional name for the set

  • category – (default: None) an optional category for that enumerated set. If you know that your iterator will stop after a finite number of steps you should set it as FiniteEnumeratedSets, conversely if you know that your iterator will run over and over you should set it as InfiniteEnumeratedSets.

  • cache – boolean (default: False) – Whether or not use a cache mechanism for the iterator. If True, then the function f is called only once.

EXAMPLES:

sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator
sage: E = EnumeratedSetFromIterator(graphs, args=(7,)); E                       # needs sage.graphs
{Graph on 7 vertices, Graph on 7 vertices, Graph on 7 vertices,
 Graph on 7 vertices, Graph on 7 vertices, ...}
sage: E.category()                                                              # needs sage.graphs
Category of facade enumerated sets
>>> from sage.all import *
>>> from sage.sets.set_from_iterator import EnumeratedSetFromIterator
>>> E = EnumeratedSetFromIterator(graphs, args=(Integer(7),)); E                       # needs sage.graphs
{Graph on 7 vertices, Graph on 7 vertices, Graph on 7 vertices,
 Graph on 7 vertices, Graph on 7 vertices, ...}
>>> E.category()                                                              # needs sage.graphs
Category of facade enumerated sets

The same example with a cache and a custom name:

sage: E = EnumeratedSetFromIterator(graphs, args=(8,), cache=True,              # needs sage.graphs
....:                               name="Graphs with 8 vertices",
....:                               category=FiniteEnumeratedSets()); E
Graphs with 8 vertices
sage: E.unrank(3)                                                               # needs sage.graphs
Graph on 8 vertices
sage: E.category()                                                              # needs sage.graphs
Category of facade finite enumerated sets
>>> from sage.all import *
>>> E = EnumeratedSetFromIterator(graphs, args=(Integer(8),), cache=True,              # needs sage.graphs
...                               name="Graphs with 8 vertices",
...                               category=FiniteEnumeratedSets()); E
Graphs with 8 vertices
>>> E.unrank(Integer(3))                                                               # needs sage.graphs
Graph on 8 vertices
>>> E.category()                                                              # needs sage.graphs
Category of facade finite enumerated sets

Note

In order to make the TestSuite works, the elements of the set should have parents.

clear_cache()[source]#

Clear the cache.

EXAMPLES:

sage: from itertools import count
sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator
sage: E = EnumeratedSetFromIterator(count, args=(1,), cache=True)
sage: e1 = E._cache; e1
lazy list [1, 2, 3, ...]
sage: E.clear_cache()
sage: E._cache
lazy list [1, 2, 3, ...]
sage: e1 is E._cache
False
>>> from sage.all import *
>>> from itertools import count
>>> from sage.sets.set_from_iterator import EnumeratedSetFromIterator
>>> E = EnumeratedSetFromIterator(count, args=(Integer(1),), cache=True)
>>> e1 = E._cache; e1
lazy list [1, 2, 3, ...]
>>> E.clear_cache()
>>> E._cache
lazy list [1, 2, 3, ...]
>>> e1 is E._cache
False
is_parent_of(x)[source]#

Test whether x is in self.

If the set is infinite, only the answer True should be expected in finite time.

EXAMPLES:

sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator
sage: P = Partitions(12, min_part=2, max_part=5)                            # needs sage.combinat
sage: E = EnumeratedSetFromIterator(P.__iter__)                             # needs sage.combinat
sage: P([5,5,2]) in E                                                       # needs sage.combinat
True
>>> from sage.all import *
>>> from sage.sets.set_from_iterator import EnumeratedSetFromIterator
>>> P = Partitions(Integer(12), min_part=Integer(2), max_part=Integer(5))                            # needs sage.combinat
>>> E = EnumeratedSetFromIterator(P.__iter__)                             # needs sage.combinat
>>> P([Integer(5),Integer(5),Integer(2)]) in E                                                       # needs sage.combinat
True
unrank(i)[source]#

Returns the element at position i.

EXAMPLES:

sage: # needs sage.graphs
sage: from sage.sets.set_from_iterator import EnumeratedSetFromIterator
sage: E = EnumeratedSetFromIterator(graphs, args=(8,), cache=True)
sage: F = EnumeratedSetFromIterator(graphs, args=(8,), cache=False)
sage: E.unrank(2)
Graph on 8 vertices
sage: E.unrank(2) == F.unrank(2)
True
>>> from sage.all import *
>>> # needs sage.graphs
>>> from sage.sets.set_from_iterator import EnumeratedSetFromIterator
>>> E = EnumeratedSetFromIterator(graphs, args=(Integer(8),), cache=True)
>>> F = EnumeratedSetFromIterator(graphs, args=(Integer(8),), cache=False)
>>> E.unrank(Integer(2))
Graph on 8 vertices
>>> E.unrank(Integer(2)) == F.unrank(Integer(2))
True
class sage.sets.set_from_iterator.EnumeratedSetFromIterator_function_decorator(f=None, name=None, **options)[source]#

Bases: Decorator

Decorator for 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, ...}
>>> from sage.all import *
>>> from sage.sets.set_from_iterator import set_from_function
>>> @set_from_function
... def f(n):
...     for i in range(n):
...         yield i**Integer(2) + i + Integer(1)
>>> f(Integer(3))
{1, 3, 7}
>>> f(Integer(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 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(); F
{1, 2, 3, 5, 8, ...}
sage: F.cardinality()
+Infinity
>>> from sage.all import *
>>> @set_from_function(category=InfiniteEnumeratedSets())
... def Fibonacci():
...     a = Integer(1); b = Integer(2)
...     while True:
...         yield a
...         a, b = b, a + b
>>> F = Fibonacci(); F
{1, 2, 3, 5, 8, ...}
>>> 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
>>> from sage.all import *
>>> @set_from_function(name="From %(m)d to %(n)d",
...                    category=FiniteEnumeratedSets())
... def f(m, n): return xsrange(m, n + Integer(1))
>>> E = f(Integer(3),Integer(10)); E
From 3 to 10
>>> E.list()
[3, 4, 5, 6, 7, 8, 9, 10]
>>> E = f(Integer(1),Integer(100)); E
From 1 to 100
>>> E.cardinality()
100
>>> f(n=Integer(100), m=Integer(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)                                                                # needs sage.graphs
Graphs on 10 vertices
sage: Graphs(10).unrank(0)                                                      # needs sage.graphs
Graph on 10 vertices
sage: Graphs(10) is Graphs(10)                                                  # needs sage.graphs
True
>>> from sage.all import *
>>> @cached_function
... @set_from_function(name="Graphs on %(n)d vertices",
...                    category=FiniteEnumeratedSets(), cache=True)
... def Graphs(n): return graphs(n)
>>> Graphs(Integer(10))                                                                # needs sage.graphs
Graphs on 10 vertices
>>> Graphs(Integer(10)).unrank(Integer(0))                                                      # needs sage.graphs
Graph on 10 vertices
>>> Graphs(Integer(10)) is Graphs(Integer(10))                                                  # needs sage.graphs
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)                                                                # needs sage.graphs
Graphs on 10 vertices
sage: Graphs(10).unrank(0)                                                      # needs sage.graphs
Graph on 10 vertices
sage: Graphs(10) is Graphs(10)                                                  # needs sage.graphs
False
>>> from sage.all import *
>>> @set_from_function(name="Graphs on %(n)d vertices",
...                    category=FiniteEnumeratedSets(), cache=True)
... @cached_function
... def Graphs(n): return graphs(n)
>>> Graphs(Integer(10))                                                                # needs sage.graphs
Graphs on 10 vertices
>>> Graphs(Integer(10)).unrank(Integer(0))                                                      # needs sage.graphs
Graph on 10 vertices
>>> Graphs(Integer(10)) is Graphs(Integer(10))                                                  # needs sage.graphs
False
class sage.sets.set_from_iterator.EnumeratedSetFromIterator_method_caller(inst, f, name=None, **options)[source]#

Bases: Decorator

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 EnumeratedSetFromIterator

class sage.sets.set_from_iterator.EnumeratedSetFromIterator_method_decorator(f=None, **options)[source]#

Bases: object

Decorator for enumerated set built from a method.

INPUT:

  • f – Optional function from which are built the enumerated sets at each call

  • name – Optional string (which may contains substitution rules from argument) or a function (args,kwds) -> string.

  • any option accepted by EnumeratedSetFromIterator.

EXAMPLES:

sage: from sage.sets.set_from_iterator import set_from_method
sage: class A():
....:     def n(self): return 12
....:     @set_from_method
....:     def f(self): return xsrange(self.n())
sage: a = A()
sage: print(a.f.__class__)
<class 'sage.sets.set_from_iterator.EnumeratedSetFromIterator_method_caller'>
sage: a.f()
{0, 1, 2, 3, 4, ...}
sage: A.f(a)
{0, 1, 2, 3, 4, ...}
>>> from sage.all import *
>>> from sage.sets.set_from_iterator import set_from_method
>>> class A():
...     def n(self): return Integer(12)
...     @set_from_method
...     def f(self): return xsrange(self.n())
>>> a = A()
>>> print(a.f.__class__)
<class 'sage.sets.set_from_iterator.EnumeratedSetFromIterator_method_caller'>
>>> a.f()
{0, 1, 2, 3, 4, ...}
>>> A.f(a)
{0, 1, 2, 3, 4, ...}

A more complicated example with a parametrized name:

sage: class B():
....:     @set_from_method(name="Graphs(%(n)d)",
....:                      category=FiniteEnumeratedSets())
....:     def graphs(self, n): return graphs(n)
sage: b = B()
sage: G3 = b.graphs(3); G3
Graphs(3)
sage: G3.cardinality()                                                          # needs sage.graphs
4
sage: G3.category()
Category of facade finite enumerated sets
sage: B.graphs(b, 3)
Graphs(3)
>>> from sage.all import *
>>> class B():
...     @set_from_method(name="Graphs(%(n)d)",
...                      category=FiniteEnumeratedSets())
...     def graphs(self, n): return graphs(n)
>>> b = B()
>>> G3 = b.graphs(Integer(3)); G3
Graphs(3)
>>> G3.cardinality()                                                          # needs sage.graphs
4
>>> G3.category()
Category of facade finite enumerated sets
>>> B.graphs(b, Integer(3))
Graphs(3)

And a last example with a name parametrized by a function:

sage: class D():
....:     def __init__(self, name): self.name = str(name)
....:     def __str__(self): return self.name
....:     @set_from_method(name=lambda self, n: str(self) * n,
....:                      category=FiniteEnumeratedSets())
....:     def subset(self, n):
....:         return xsrange(n)
sage: d = D('a')
sage: E = d.subset(3); E
aaa
sage: E.list()
[0, 1, 2]
sage: F = d.subset(n=10); F
aaaaaaaaaa
sage: F.list()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> from sage.all import *
>>> class D():
...     def __init__(self, name): self.name = str(name)
...     def __str__(self): return self.name
...     @set_from_method(name=lambda self, n: str(self) * n,
...                      category=FiniteEnumeratedSets())
...     def subset(self, n):
...         return xsrange(n)
>>> d = D('a')
>>> E = d.subset(Integer(3)); E
aaa
>>> E.list()
[0, 1, 2]
>>> F = d.subset(n=Integer(10)); F
aaaaaaaaaa
>>> F.list()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Todo

It is not yet possible to use set_from_method in conjunction with cached_method.

sage.sets.set_from_iterator.set_from_function[source]#

alias of EnumeratedSetFromIterator_function_decorator

sage.sets.set_from_iterator.set_from_method[source]#

alias of EnumeratedSetFromIterator_method_decorator