r"""
Facade Sets
"""
from sage.misc.cachefunc import cached_method
from sage.categories.category_singleton import Category_singleton
from sage.categories.category import Category
class FacadeSets(Category_singleton):
r"""
The category of facade sets
A *facade set* is a parent ``P`` whose elements actually belong to
some other parent::
sage: P = Sets().example(); P
Set of prime numbers (basic implementation)
sage: p = Sets().example().an_element(); p
47
sage: p in P
True
sage: p.parent()
Integer Ring
Typical use cases include modeling a subset of an existing
parent::
sage: Sets().Facades().example()
An example of facade set: the monoid of positive integers
or the union of several parents::
sage: Sets().Facades().example("union")
An example of a facade set: the integers completed by +-infinity
or endowing a parent with more (or less!) structure::
sage: Posets().example("facade")
An example of a facade poset: the positive integers ordered by divisibility
Let us consider one of the examples above in detail: the partially ordered
set `P` of positive integers w.r.t. divisibility order. There are two
options for representing its elements:
1. as plain integers
2. as integers, modified to be aware that their parent is `P`
The advantage of 1. is that one needs not to do conversions back and
forth between `P` and `\ZZ`. The disadvantage is that this
introduces an ambiguity when writing `2 < 3`::
sage: 2 < 3
True
To raise this ambiguity, one needs to explicitely specify the order
as in `2 <_P 3`::
sage: P = Posets().example("facade")
sage: P.lt(2,3)
False
In short `P` being a facade parent is one of the programmatic
counterpart (with e.g. coercions) of the usual mathematical idiom:
"for ease of notation, we identify an element of `P` with the
corresponding integer". Too many identifications lead to
confusion; the lack thereof leads to heavy, if not obfuscated,
notations. Finding the right balance is an art, and even though
there are common guidelines, it is ultimately up to the writer to
choose which identifications to do. This is no different in code.
.. seealso::
::
sage: Sets().example("facade")
Set of prime numbers (facade implementation)
sage: Sets().example("inherits")
Set of prime numbers
sage: Sets().example("wrapper")
Set of prime numbers (wrapper implementation)
.. rubric:: Specifications
A parent which is a facade must either:
- call :meth:`Parent.__init__` using the ``facade`` parameter to
specify a parent, or tuple thereof.
- overload the method :meth:`~FacadeSets.ParentMethods.facade_for`.
.. note:: the concept of facade parents was originally introduced
in the computer algebra system MuPAD.
"""
@cached_method
def super_categories(self):
r"""
Returns the super categories of ``self``, as per
:meth:`Category.super_categories`.
EXAMPLES::
sage: Sets().Facades().super_categories()
[Category of sets]
"""
from sage.categories.sets_cat import Sets
return [Sets()]
def example(self, choice='subset'):
r"""
Returns an example of facade set, as per
:meth:`Category.example()
<sage.categories.category.Category.example>`.
INPUT:
- ``choice`` -- 'union' or 'subset' (default: 'subset').
EXAMPLES::
sage: Sets().Facades().example()
An example of facade set: the monoid of positive integers
sage: Sets().Facades().example(choice='union')
An example of a facade set: the integers completed by +-infinity
sage: Sets().Facades().example(choice='subset')
An example of facade set: the monoid of positive integers
"""
import sage.categories.examples.facade_sets as examples
if choice == "union":
return examples.IntegersCompletion()
elif choice == 'subset':
return examples.PositiveIntegerMonoid()
else:
raise TypeError, "choice should be 'union' or 'subset'"
class ParentMethods:
def _element_constructor_(self, element):
"""
Coerce ``element`` into ``self``
INPUT:
- ``element`` -- any object
This default implementation returns ``element`` if
``self`` is a facade for ``parent(element)`. Otherwise it
attempts in turn to coerce ``element`` into each parent
``self`` is a facade for.
This implementation is only valid for a facade parent
which models the full union of the parents it is a facade
for. Other facade parents should redefine
:meth:`element_constructor` appropriately.
EXAMPLES::
sage: S = Sets().Facades().example("union"); S
An example of a facade set: the integers completed by +-infinity
sage: S(1)
1
sage: S(1/2)
Traceback (most recent call last):
...
ValueError: Can't coerce `1/2` in any parent `An example of a facade set: the integers completed by +-infinity` is a facade for
sage: S(2/1)
2
sage: S(2/1).parent()
Integer Ring
sage: S(int(1))
1
sage: S(int(1)).parent()
Integer Ring
Facade parents that model strict subsets should redefine
:meth:`element_constructor`::
sage: S = Sets().Facades().example(); S
An example of facade set: the monoid of positive integers
sage: S(-1)
Traceback (most recent call last):
...
ValueError: %s should be positive
"""
if self.is_parent_of(element):
return element
else:
parents = self.facade_for()
if parents is True:
return NotImplementedError
for parent in self.facade_for():
try:
return parent(element)
except:
pass
raise ValueError, "Can't coerce `%s` in any parent `%s` is a facade for"%(element, self)
def facade_for(self):
"""
Returns all the parents this set is a facade for
This default implementation assumes that ``self`` has
an attribute ``_facade_for``, typically initialized by
:meth:`Parent.__init__`.
EXAMPLES::
sage: S = Sets().Facades().example(); S
An example of facade set: the monoid of positive integers
sage: S.facade_for()
(Integer Ring,)
"""
return self._facade_for
def is_parent_of(self, element):
"""
Returns whether ``self`` is the parent of ``element``
INPUT:
- ``element`` -- any object
Since ``self`` is a facade domain, this actually tests
whether the parent of ``element`` is any of the parent
``self`` is a facade for.
EXAMPLES::
sage: S = Sets().Facades().example(); S
An example of facade set: the monoid of positive integers
sage: S.is_parent_of(1)
True
sage: S.is_parent_of(1/2)
False
This method differs from :meth:`__contains__` in two
ways. First, this does not take into account the fact
that ``self`` may be a strict subset of the parent(s)
it is a facade for::
sage: -1 in S, S.is_parent_of(-1)
(False, True)
Furthermore, there is no coercion attempted::
sage: int(1) in S, S.is_parent_of(int(1))
(True, False)
.. warning::
this implementation does not handle facade parents of facade
parents. Is this a feature we want generically?
"""
parents = self.facade_for()
if parents is True:
return True
from sage.structure.element import parent
return parent(element) in parents
def __contains__(self, element):
"""
Membership testing
Returns whether ``element`` is in one of the parents
``self`` is a facade for.
.. warning:: this default implementation is currently
overriden by :meth:`Parent.__contains__`.
EXAMPLES::
sage: S = Sets().Facades().example("union"); S
An example of a facade set: the integers completed by +-infinity
sage: 1 in S, -5 in S, oo in S, -oo in S, int(1) in S, 2/1 in S
(True, True, True, True, True, True)
sage: 1/2 in S, "bla" in S
(False, False)
"""
return any(element in parent for parent in self.facade_for())
def _an_element_(self):
"""
Try to return an element of ``self``, as per
:meth:`Sets.ParentMethods.an_element`.
For each parent ``self`` is a facade for, this default
implementation tries the method ``an_element`` until it finds an
element in ``self``. If none is found raise a
``NotImplementedError``.
EXAMPLES::
sage: S = Sets().Facades().example(); S
An example of facade set: the monoid of positive integers
sage: S.an_element()
1
"""
for parent in self.facade_for():
x = parent.an_element()
if x in self:
return x
raise NotImplementedError