Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/categories/facade_sets.py
4057 views
1
r"""
2
Facade Sets
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2010 Nicolas M. Thiery <nthiery at users.sf.net>
6
#
7
# Distributed under the terms of the GNU General Public License (GPL)
8
# http://www.gnu.org/licenses/
9
#******************************************************************************
10
11
from sage.misc.cachefunc import cached_method
12
from sage.categories.category_singleton import Category_singleton
13
from sage.categories.category import Category
14
15
class FacadeSets(Category_singleton):
16
r"""
17
The category of facade sets
18
19
A *facade set* is a parent ``P`` whose elements actually belong to
20
some other parent::
21
22
sage: P = Sets().example(); P
23
Set of prime numbers (basic implementation)
24
sage: p = Sets().example().an_element(); p
25
47
26
sage: p in P
27
True
28
sage: p.parent()
29
Integer Ring
30
31
Typical use cases include modeling a subset of an existing
32
parent::
33
34
sage: Sets().Facades().example()
35
An example of facade set: the monoid of positive integers
36
37
or the union of several parents::
38
39
sage: Sets().Facades().example("union")
40
An example of a facade set: the integers completed by +-infinity
41
42
or endowing a parent with more (or less!) structure::
43
44
sage: Posets().example("facade")
45
An example of a facade poset: the positive integers ordered by divisibility
46
47
Let us consider one of the examples above in detail: the partially ordered
48
set `P` of positive integers w.r.t. divisibility order. There are two
49
options for representing its elements:
50
51
1. as plain integers
52
2. as integers, modified to be aware that their parent is `P`
53
54
The advantage of 1. is that one needs not to do conversions back and
55
forth between `P` and `\ZZ`. The disadvantage is that this
56
introduces an ambiguity when writing `2 < 3`::
57
58
sage: 2 < 3
59
True
60
61
To raise this ambiguity, one needs to explicitely specify the order
62
as in `2 <_P 3`::
63
64
65
sage: P = Posets().example("facade")
66
sage: P.lt(2,3)
67
False
68
69
In short `P` being a facade parent is one of the programmatic
70
counterpart (with e.g. coercions) of the usual mathematical idiom:
71
"for ease of notation, we identify an element of `P` with the
72
corresponding integer". Too many identifications lead to
73
confusion; the lack thereof leads to heavy, if not obfuscated,
74
notations. Finding the right balance is an art, and even though
75
there are common guidelines, it is ultimately up to the writer to
76
choose which identifications to do. This is no different in code.
77
78
.. seealso::
79
80
::
81
82
sage: Sets().example("facade")
83
Set of prime numbers (facade implementation)
84
sage: Sets().example("inherits")
85
Set of prime numbers
86
sage: Sets().example("wrapper")
87
Set of prime numbers (wrapper implementation)
88
89
.. rubric:: Specifications
90
91
A parent which is a facade must either:
92
93
- call :meth:`Parent.__init__` using the ``facade`` parameter to
94
specify a parent, or tuple thereof.
95
- overload the method :meth:`~FacadeSets.ParentMethods.facade_for`.
96
97
.. note:: the concept of facade parents was originally introduced
98
in the computer algebra system MuPAD.
99
"""
100
101
@cached_method
102
def super_categories(self):
103
r"""
104
Returns the super categories of ``self``, as per
105
:meth:`Category.super_categories`.
106
107
EXAMPLES::
108
109
sage: Sets().Facades().super_categories()
110
[Category of sets]
111
"""
112
from sage.categories.sets_cat import Sets
113
return [Sets()]
114
115
def example(self, choice='subset'):
116
r"""
117
Returns an example of facade set, as per
118
:meth:`Category.example()
119
<sage.categories.category.Category.example>`.
120
121
INPUT:
122
123
- ``choice`` -- 'union' or 'subset' (default: 'subset').
124
125
EXAMPLES::
126
127
sage: Sets().Facades().example()
128
An example of facade set: the monoid of positive integers
129
sage: Sets().Facades().example(choice='union')
130
An example of a facade set: the integers completed by +-infinity
131
sage: Sets().Facades().example(choice='subset')
132
An example of facade set: the monoid of positive integers
133
"""
134
import sage.categories.examples.facade_sets as examples
135
if choice == "union":
136
return examples.IntegersCompletion()
137
elif choice == 'subset':
138
return examples.PositiveIntegerMonoid()
139
else:
140
raise TypeError, "choice should be 'union' or 'subset'"
141
142
class ParentMethods:
143
144
def _element_constructor_(self, element):
145
"""
146
Coerce ``element`` into ``self``
147
148
INPUT:
149
150
- ``element`` -- any object
151
152
This default implementation returns ``element`` if
153
``self`` is a facade for ``parent(element)`. Otherwise it
154
attempts in turn to coerce ``element`` into each parent
155
``self`` is a facade for.
156
157
This implementation is only valid for a facade parent
158
which models the full union of the parents it is a facade
159
for. Other facade parents should redefine
160
:meth:`element_constructor` appropriately.
161
162
EXAMPLES::
163
164
sage: S = Sets().Facades().example("union"); S
165
An example of a facade set: the integers completed by +-infinity
166
sage: S(1)
167
1
168
sage: S(1/2)
169
Traceback (most recent call last):
170
...
171
ValueError: Can't coerce `1/2` in any parent `An example of a facade set: the integers completed by +-infinity` is a facade for
172
sage: S(2/1)
173
2
174
sage: S(2/1).parent()
175
Integer Ring
176
sage: S(int(1))
177
1
178
sage: S(int(1)).parent()
179
Integer Ring
180
181
Facade parents that model strict subsets should redefine
182
:meth:`element_constructor`::
183
184
sage: S = Sets().Facades().example(); S
185
An example of facade set: the monoid of positive integers
186
sage: S(-1)
187
Traceback (most recent call last):
188
...
189
ValueError: %s should be positive
190
"""
191
if self.is_parent_of(element):
192
return element
193
else:
194
parents = self.facade_for()
195
if parents is True:
196
return NotImplementedError
197
for parent in self.facade_for():
198
try:
199
return parent(element)
200
except:
201
pass
202
raise ValueError, "Can't coerce `%s` in any parent `%s` is a facade for"%(element, self)
203
204
def facade_for(self):
205
"""
206
Returns all the parents this set is a facade for
207
208
This default implementation assumes that ``self`` has
209
an attribute ``_facade_for``, typically initialized by
210
:meth:`Parent.__init__`.
211
212
EXAMPLES::
213
214
sage: S = Sets().Facades().example(); S
215
An example of facade set: the monoid of positive integers
216
sage: S.facade_for()
217
(Integer Ring,)
218
"""
219
return self._facade_for
220
221
def is_parent_of(self, element):
222
"""
223
Returns whether ``self`` is the parent of ``element``
224
225
INPUT:
226
227
- ``element`` -- any object
228
229
Since ``self`` is a facade domain, this actually tests
230
whether the parent of ``element`` is any of the parent
231
``self`` is a facade for.
232
233
EXAMPLES::
234
235
sage: S = Sets().Facades().example(); S
236
An example of facade set: the monoid of positive integers
237
sage: S.is_parent_of(1)
238
True
239
sage: S.is_parent_of(1/2)
240
False
241
242
This method differs from :meth:`__contains__` in two
243
ways. First, this does not take into account the fact
244
that ``self`` may be a strict subset of the parent(s)
245
it is a facade for::
246
247
sage: -1 in S, S.is_parent_of(-1)
248
(False, True)
249
250
Furthermore, there is no coercion attempted::
251
252
sage: int(1) in S, S.is_parent_of(int(1))
253
(True, False)
254
255
.. warning::
256
257
this implementation does not handle facade parents of facade
258
parents. Is this a feature we want generically?
259
"""
260
parents = self.facade_for()
261
if parents is True:
262
return True
263
from sage.structure.element import parent
264
return parent(element) in parents
265
266
def __contains__(self, element):
267
"""
268
Membership testing
269
270
Returns whether ``element`` is in one of the parents
271
``self`` is a facade for.
272
273
.. warning:: this default implementation is currently
274
overriden by :meth:`Parent.__contains__`.
275
276
EXAMPLES::
277
278
sage: S = Sets().Facades().example("union"); S
279
An example of a facade set: the integers completed by +-infinity
280
sage: 1 in S, -5 in S, oo in S, -oo in S, int(1) in S, 2/1 in S
281
(True, True, True, True, True, True)
282
sage: 1/2 in S, "bla" in S
283
(False, False)
284
"""
285
return any(element in parent for parent in self.facade_for())
286
287
def _an_element_(self):
288
"""
289
Try to return an element of ``self``, as per
290
:meth:`Sets.ParentMethods.an_element`.
291
292
For each parent ``self`` is a facade for, this default
293
implementation tries the method ``an_element`` until it finds an
294
element in ``self``. If none is found raise a
295
``NotImplementedError``.
296
297
EXAMPLES::
298
299
sage: S = Sets().Facades().example(); S
300
An example of facade set: the monoid of positive integers
301
sage: S.an_element()
302
1
303
"""
304
for parent in self.facade_for():
305
x = parent.an_element()
306
if x in self:
307
return x
308
raise NotImplementedError
309
310
311
312