passagemath-objects 10.6.45__cp313-cp313-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-objects might be problematic. Click here for more details.
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.45.dist-info/METADATA +115 -0
- passagemath_objects-10.6.45.dist-info/RECORD +280 -0
- passagemath_objects-10.6.45.dist-info/WHEEL +5 -0
- passagemath_objects-10.6.45.dist-info/top_level.txt +3 -0
- passagemath_objects.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- sage/all__sagemath_objects.py +37 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cpython-313-x86_64-linux-musl.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-313-x86_64-linux-musl.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +62 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2876 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2106 -0
- sage/categories/morphism.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3290 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +19 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cpython-313-x86_64-linux-musl.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-313-x86_64-linux-musl.so +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cpython-313-x86_64-linux-musl.so +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +275 -0
- sage/misc/sage_timeit_class.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cpython-313-x86_64-linux-musl.so +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cpython-313-x86_64-linux-musl.so +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +4 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
|
@@ -0,0 +1,3290 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
r"""
|
|
3
|
+
Sets
|
|
4
|
+
"""
|
|
5
|
+
# ****************************************************************************
|
|
6
|
+
# Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu>
|
|
7
|
+
# William Stein <wstein@math.ucsd.edu>
|
|
8
|
+
# 2008 Teresa Gomez-Diaz (CNRS) <Teresa.Gomez-Diaz@univ-mlv.fr>
|
|
9
|
+
# 2008-2017 Nicolas M. Thiery <nthiery at users.sf.net>
|
|
10
|
+
# 2009 Mike Hansen
|
|
11
|
+
# 2010 Florent Hivert
|
|
12
|
+
# 2010 William Laffin
|
|
13
|
+
# 2012 Franco Saliola
|
|
14
|
+
# 2013 Sara Billey
|
|
15
|
+
# 2013 Simon King
|
|
16
|
+
# 2013-2016 Julian Rüth
|
|
17
|
+
# 2014 Darij Grinberg
|
|
18
|
+
# 2014 Peter Bruin
|
|
19
|
+
# 2014-2021 Frédéric Chapoton
|
|
20
|
+
# 2014-2021 Travis Scrimshaw
|
|
21
|
+
# 2015 Daniel Krenn
|
|
22
|
+
# 2015 Vincent Delecroix
|
|
23
|
+
# 2015-2016 Jori Mäntysalo
|
|
24
|
+
# 2016 Kwankyu Lee
|
|
25
|
+
# 2018 Vincent Klein
|
|
26
|
+
# 2019 Markus Wageringel
|
|
27
|
+
# 2020-2021 Matthias Koeppe
|
|
28
|
+
#
|
|
29
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
30
|
+
# https://www.gnu.org/licenses/
|
|
31
|
+
# *****************************************************************************
|
|
32
|
+
|
|
33
|
+
from sage.misc.cachefunc import cached_method
|
|
34
|
+
from sage.misc.sage_unittest import TestSuite
|
|
35
|
+
from sage.misc.abstract_method import abstract_method
|
|
36
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
37
|
+
from sage.misc.lazy_import import lazy_import, LazyImport
|
|
38
|
+
from sage.misc.lazy_format import LazyFormat
|
|
39
|
+
from sage.categories.category import Category
|
|
40
|
+
from sage.categories.category_singleton import Category_singleton
|
|
41
|
+
# Do not use sage.categories.all here to avoid initialization loop
|
|
42
|
+
from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
|
|
43
|
+
from sage.categories.subquotients import SubquotientsCategory
|
|
44
|
+
from sage.categories.quotients import QuotientsCategory
|
|
45
|
+
from sage.categories.subobjects import SubobjectsCategory
|
|
46
|
+
from sage.categories.isomorphic_objects import IsomorphicObjectsCategory
|
|
47
|
+
from sage.categories.algebra_functor import AlgebrasCategory
|
|
48
|
+
from sage.categories.cartesian_product import CartesianProductsCategory, CartesianProductFunctor
|
|
49
|
+
from sage.categories.realizations import RealizationsCategory, Category_realization_of_parent
|
|
50
|
+
from sage.categories.with_realizations import WithRealizationsCategory
|
|
51
|
+
from sage.categories.category_with_axiom import CategoryWithAxiom
|
|
52
|
+
lazy_import('sage.sets.cartesian_product', 'CartesianProduct')
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def print_compare(x, y):
|
|
56
|
+
"""
|
|
57
|
+
Helper method used in
|
|
58
|
+
:meth:`Sets.ParentMethods._test_elements_eq_symmetric`,
|
|
59
|
+
:meth:`Sets.ParentMethods._test_elements_eq_tranisitive`.
|
|
60
|
+
|
|
61
|
+
INPUT:
|
|
62
|
+
|
|
63
|
+
- ``x`` -- an element
|
|
64
|
+
|
|
65
|
+
- ``y`` -- an element
|
|
66
|
+
|
|
67
|
+
EXAMPLES::
|
|
68
|
+
|
|
69
|
+
sage: from sage.categories.sets_cat import print_compare
|
|
70
|
+
sage: print_compare(1,2)
|
|
71
|
+
1 != 2
|
|
72
|
+
sage: print_compare(1,1)
|
|
73
|
+
1 == 1
|
|
74
|
+
"""
|
|
75
|
+
if x == y:
|
|
76
|
+
return LazyFormat("%s == %s") % (x, y)
|
|
77
|
+
else:
|
|
78
|
+
return LazyFormat("%s != %s") % (x, y)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class EmptySetError(ValueError):
|
|
82
|
+
"""
|
|
83
|
+
Exception raised when some operation can't be performed on the empty set.
|
|
84
|
+
|
|
85
|
+
EXAMPLES::
|
|
86
|
+
|
|
87
|
+
sage: def first_element(st):
|
|
88
|
+
....: if not st: raise EmptySetError("no elements")
|
|
89
|
+
....: else: return st[0]
|
|
90
|
+
sage: first_element(Set((1,2,3)))
|
|
91
|
+
1
|
|
92
|
+
sage: first_element(Set([]))
|
|
93
|
+
Traceback (most recent call last):
|
|
94
|
+
...
|
|
95
|
+
EmptySetError: no elements
|
|
96
|
+
"""
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class Sets(Category_singleton):
|
|
101
|
+
r"""
|
|
102
|
+
The category of sets.
|
|
103
|
+
|
|
104
|
+
The base category for collections of elements with = (equality).
|
|
105
|
+
|
|
106
|
+
This is also the category whose objects are all parents.
|
|
107
|
+
|
|
108
|
+
EXAMPLES::
|
|
109
|
+
|
|
110
|
+
sage: Sets()
|
|
111
|
+
Category of sets
|
|
112
|
+
sage: Sets().super_categories()
|
|
113
|
+
[Category of sets with partial maps]
|
|
114
|
+
sage: Sets().all_super_categories()
|
|
115
|
+
[Category of sets, Category of sets with partial maps, Category of objects]
|
|
116
|
+
|
|
117
|
+
Let us consider an example of set::
|
|
118
|
+
|
|
119
|
+
sage: P = Sets().example("inherits")
|
|
120
|
+
sage: P
|
|
121
|
+
Set of prime numbers
|
|
122
|
+
|
|
123
|
+
See ``P??`` for the code.
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
P is in the category of sets::
|
|
127
|
+
|
|
128
|
+
sage: P.category()
|
|
129
|
+
Category of sets
|
|
130
|
+
|
|
131
|
+
and therefore gets its methods from the following classes::
|
|
132
|
+
|
|
133
|
+
sage: for cl in P.__class__.mro(): print(cl)
|
|
134
|
+
<class 'sage.categories.examples.sets_cat.PrimeNumbers_Inherits_with_category'>
|
|
135
|
+
<class 'sage.categories.examples.sets_cat.PrimeNumbers_Inherits'>
|
|
136
|
+
<class 'sage.categories.examples.sets_cat.PrimeNumbers_Abstract'>
|
|
137
|
+
<class 'sage.structure.unique_representation.UniqueRepresentation'>
|
|
138
|
+
<class 'sage.misc.fast_methods.WithEqualityById'>
|
|
139
|
+
<class 'sage.structure.unique_representation.CachedRepresentation'>
|
|
140
|
+
<class 'sage.structure.unique_representation.WithPicklingByInitArgs'>
|
|
141
|
+
<class 'sage.structure.parent.Parent'>
|
|
142
|
+
<class 'sage.structure.category_object.CategoryObject'>
|
|
143
|
+
<class 'sage.structure.sage_object.SageObject'>
|
|
144
|
+
<class 'sage.categories.sets_cat.Sets.parent_class'>
|
|
145
|
+
<class 'sage.categories.sets_with_partial_maps.SetsWithPartialMaps.parent_class'>
|
|
146
|
+
<class 'sage.categories.objects.Objects.parent_class'>
|
|
147
|
+
<class 'object'>
|
|
148
|
+
|
|
149
|
+
We run some generic checks on P::
|
|
150
|
+
|
|
151
|
+
sage: TestSuite(P).run(verbose=True) # needs sage.libs.pari
|
|
152
|
+
running ._test_an_element() . . . pass
|
|
153
|
+
running ._test_cardinality() . . . pass
|
|
154
|
+
running ._test_category() . . . pass
|
|
155
|
+
running ._test_construction() . . . pass
|
|
156
|
+
running ._test_elements() . . .
|
|
157
|
+
Running the test suite of self.an_element()
|
|
158
|
+
running ._test_category() . . . pass
|
|
159
|
+
running ._test_eq() . . . pass
|
|
160
|
+
running ._test_new() . . . pass
|
|
161
|
+
running ._test_not_implemented_methods() . . . pass
|
|
162
|
+
running ._test_pickling() . . . pass
|
|
163
|
+
pass
|
|
164
|
+
running ._test_elements_eq_reflexive() . . . pass
|
|
165
|
+
running ._test_elements_eq_symmetric() . . . pass
|
|
166
|
+
running ._test_elements_eq_transitive() . . . pass
|
|
167
|
+
running ._test_elements_neq() . . . pass
|
|
168
|
+
running ._test_eq() . . . pass
|
|
169
|
+
running ._test_new() . . . pass
|
|
170
|
+
running ._test_not_implemented_methods() . . . pass
|
|
171
|
+
running ._test_pickling() . . . pass
|
|
172
|
+
running ._test_some_elements() . . . pass
|
|
173
|
+
|
|
174
|
+
Now, we manipulate some elements of P::
|
|
175
|
+
|
|
176
|
+
sage: P.an_element()
|
|
177
|
+
47
|
|
178
|
+
sage: x = P(3)
|
|
179
|
+
sage: x.parent()
|
|
180
|
+
Set of prime numbers
|
|
181
|
+
sage: x in P, 4 in P
|
|
182
|
+
(True, False)
|
|
183
|
+
sage: x.is_prime()
|
|
184
|
+
True
|
|
185
|
+
|
|
186
|
+
They get their methods from the following classes::
|
|
187
|
+
|
|
188
|
+
sage: for cl in x.__class__.mro(): print(cl)
|
|
189
|
+
<class 'sage.categories.examples.sets_cat.PrimeNumbers_Inherits_with_category.element_class'>
|
|
190
|
+
<class 'sage.categories.examples.sets_cat.PrimeNumbers_Inherits.Element'>
|
|
191
|
+
<class 'sage.rings.integer.IntegerWrapper'>
|
|
192
|
+
<class 'sage.rings.integer.Integer'>
|
|
193
|
+
<class 'sage.structure.element.EuclideanDomainElement'>
|
|
194
|
+
<class 'sage.structure.element.PrincipalIdealDomainElement'>
|
|
195
|
+
<class 'sage.structure.element.DedekindDomainElement'>
|
|
196
|
+
<class 'sage.structure.element.IntegralDomainElement'>
|
|
197
|
+
<class 'sage.structure.element.CommutativeRingElement'>
|
|
198
|
+
<class 'sage.structure.element.RingElement'>
|
|
199
|
+
<class 'sage.structure.element.ModuleElement'>
|
|
200
|
+
<class 'sage.categories.examples.sets_cat.PrimeNumbers_Abstract.Element'>
|
|
201
|
+
<class 'sage.structure.element.Element'>
|
|
202
|
+
<class 'sage.structure.sage_object.SageObject'>
|
|
203
|
+
<class 'sage.categories.sets_cat.Sets.element_class'>
|
|
204
|
+
<class 'sage.categories.sets_with_partial_maps.SetsWithPartialMaps.element_class'>
|
|
205
|
+
<class 'sage.categories.objects.Objects.element_class'>
|
|
206
|
+
<... 'object'>
|
|
207
|
+
|
|
208
|
+
FIXME: Objects.element_class is not very meaningful ...
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
TESTS::
|
|
212
|
+
|
|
213
|
+
sage: TestSuite(Sets()).run()
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
def super_categories(self):
|
|
217
|
+
r"""
|
|
218
|
+
We include SetsWithPartialMaps between Sets and Objects so that we
|
|
219
|
+
can define morphisms between sets that are only partially defined.
|
|
220
|
+
This is also to have the Homset constructor not complain that
|
|
221
|
+
SetsWithPartialMaps is not a supercategory of Fields, for example.
|
|
222
|
+
|
|
223
|
+
EXAMPLES::
|
|
224
|
+
|
|
225
|
+
sage: Sets().super_categories()
|
|
226
|
+
[Category of sets with partial maps]
|
|
227
|
+
"""
|
|
228
|
+
return [SetsWithPartialMaps()]
|
|
229
|
+
|
|
230
|
+
def _call_(self, X, enumerated_set=False):
|
|
231
|
+
r"""
|
|
232
|
+
Construct an object in this category from the data ``X``.
|
|
233
|
+
|
|
234
|
+
INPUT:
|
|
235
|
+
|
|
236
|
+
- ``X`` -- an object to be converted into a set
|
|
237
|
+
|
|
238
|
+
- ``enumerated_set`` -- if set to ``True`` and the input is either a
|
|
239
|
+
Python tuple or a Python list then the output will be a finite
|
|
240
|
+
enumerated set.
|
|
241
|
+
|
|
242
|
+
EXAMPLES::
|
|
243
|
+
|
|
244
|
+
sage: Sets()(ZZ)
|
|
245
|
+
Integer Ring
|
|
246
|
+
sage: Sets()([1, 2, 3])
|
|
247
|
+
{1, 2, 3}
|
|
248
|
+
|
|
249
|
+
sage: S = Sets()([1, 2, 3]); S.category()
|
|
250
|
+
Category of finite enumerated sets
|
|
251
|
+
sage: S = Sets()([1, 2, 3], enumerated_set=True); S.category()
|
|
252
|
+
Category of facade finite enumerated sets
|
|
253
|
+
|
|
254
|
+
.. NOTE::
|
|
255
|
+
|
|
256
|
+
Using ``Sets()(A)`` used to implement some sort of forgetful functor
|
|
257
|
+
into the ``Sets()`` category. This feature has been removed, because
|
|
258
|
+
it was not consistent with the semantic of :meth:`Category.__call__`.
|
|
259
|
+
Proper forgetful functors will eventually be implemented, with
|
|
260
|
+
another syntax.
|
|
261
|
+
"""
|
|
262
|
+
if enumerated_set and type(X) in (tuple, list, range):
|
|
263
|
+
from sage.categories.enumerated_sets import EnumeratedSets
|
|
264
|
+
return EnumeratedSets()(X)
|
|
265
|
+
from sage.sets.set import Set
|
|
266
|
+
return Set(X)
|
|
267
|
+
|
|
268
|
+
def example(self, choice=None):
|
|
269
|
+
"""
|
|
270
|
+
Return examples of objects of ``Sets()``, as per
|
|
271
|
+
:meth:`Category.example()
|
|
272
|
+
<sage.categories.category.Category.example>`.
|
|
273
|
+
|
|
274
|
+
EXAMPLES::
|
|
275
|
+
|
|
276
|
+
sage: Sets().example()
|
|
277
|
+
Set of prime numbers (basic implementation)
|
|
278
|
+
|
|
279
|
+
sage: Sets().example("inherits")
|
|
280
|
+
Set of prime numbers
|
|
281
|
+
|
|
282
|
+
sage: Sets().example("facade")
|
|
283
|
+
Set of prime numbers (facade implementation)
|
|
284
|
+
|
|
285
|
+
sage: Sets().example("wrapper")
|
|
286
|
+
Set of prime numbers (wrapper implementation)
|
|
287
|
+
"""
|
|
288
|
+
if choice is None:
|
|
289
|
+
from sage.categories.examples.sets_cat import PrimeNumbers
|
|
290
|
+
return PrimeNumbers()
|
|
291
|
+
elif choice == "inherits":
|
|
292
|
+
from sage.categories.examples.sets_cat import PrimeNumbers_Inherits
|
|
293
|
+
return PrimeNumbers_Inherits()
|
|
294
|
+
elif choice == "facade":
|
|
295
|
+
from sage.categories.examples.sets_cat import PrimeNumbers_Facade
|
|
296
|
+
return PrimeNumbers_Facade()
|
|
297
|
+
elif choice == "wrapper":
|
|
298
|
+
from sage.categories.examples.sets_cat import PrimeNumbers_Wrapper
|
|
299
|
+
return PrimeNumbers_Wrapper()
|
|
300
|
+
else:
|
|
301
|
+
raise ValueError("unknown choice")
|
|
302
|
+
|
|
303
|
+
class SubcategoryMethods:
|
|
304
|
+
|
|
305
|
+
@cached_method
|
|
306
|
+
def CartesianProducts(self):
|
|
307
|
+
r"""
|
|
308
|
+
Return the full subcategory of the objects of ``self``
|
|
309
|
+
constructed as Cartesian products.
|
|
310
|
+
|
|
311
|
+
.. SEEALSO::
|
|
312
|
+
|
|
313
|
+
- :class:`.cartesian_product.CartesianProductFunctor`
|
|
314
|
+
- :class:`~.covariant_functorial_construction.RegressiveCovariantFunctorialConstruction`
|
|
315
|
+
|
|
316
|
+
EXAMPLES::
|
|
317
|
+
|
|
318
|
+
sage: Sets().CartesianProducts()
|
|
319
|
+
Category of Cartesian products of sets
|
|
320
|
+
sage: Semigroups().CartesianProducts()
|
|
321
|
+
Category of Cartesian products of semigroups
|
|
322
|
+
sage: EuclideanDomains().CartesianProducts()
|
|
323
|
+
Category of Cartesian products of commutative rings
|
|
324
|
+
"""
|
|
325
|
+
return CartesianProductsCategory.category_of(self)
|
|
326
|
+
|
|
327
|
+
@cached_method
|
|
328
|
+
def Subquotients(self):
|
|
329
|
+
r"""
|
|
330
|
+
Return the full subcategory of the objects of ``self``
|
|
331
|
+
constructed as subquotients.
|
|
332
|
+
|
|
333
|
+
Given a concrete category ``self == As()`` (i.e. a subcategory
|
|
334
|
+
of ``Sets()``), ``As().Subquotients()`` returns the category
|
|
335
|
+
of objects of ``As()`` endowed with a distinguished
|
|
336
|
+
description as subquotient of some other object of ``As()``.
|
|
337
|
+
|
|
338
|
+
EXAMPLES::
|
|
339
|
+
|
|
340
|
+
sage: Monoids().Subquotients()
|
|
341
|
+
Category of subquotients of monoids
|
|
342
|
+
|
|
343
|
+
A parent `A` in ``As()`` is further in
|
|
344
|
+
``As().Subquotients()`` if there is a distinguished parent
|
|
345
|
+
`B` in ``As()``, called the *ambient set*, a subobject
|
|
346
|
+
`B'` of `B`, and a pair of maps:
|
|
347
|
+
|
|
348
|
+
.. MATH::
|
|
349
|
+
|
|
350
|
+
l: A \to B' \text{ and } r: B' \to A
|
|
351
|
+
|
|
352
|
+
called respectively the *lifting map* and *retract map*
|
|
353
|
+
such that `r \circ l` is the identity of `A` and `r` is a
|
|
354
|
+
morphism in ``As()``.
|
|
355
|
+
|
|
356
|
+
.. TODO:: Draw the typical commutative diagram.
|
|
357
|
+
|
|
358
|
+
It follows that, for each operation `op` of the category,
|
|
359
|
+
we have some property like:
|
|
360
|
+
|
|
361
|
+
.. MATH::
|
|
362
|
+
|
|
363
|
+
op_A(e) = r(op_B(l(e))), \text{ for all } e\in A
|
|
364
|
+
|
|
365
|
+
This allows for implementing the operations on `A` from
|
|
366
|
+
those on `B`.
|
|
367
|
+
|
|
368
|
+
The two most common use cases are:
|
|
369
|
+
|
|
370
|
+
- *homomorphic images* (or *quotients*), when `B'=B`,
|
|
371
|
+
`r` is an homomorphism from `B` to `A` (typically a
|
|
372
|
+
canonical quotient map), and `l` a section of it (not
|
|
373
|
+
necessarily a homomorphism); see :meth:`Quotients`;
|
|
374
|
+
|
|
375
|
+
- *subobjects* (up to an isomorphism), when `l` is an
|
|
376
|
+
embedding from `A` into `B`; in this case, `B'` is
|
|
377
|
+
typically isomorphic to `A` through the inverse
|
|
378
|
+
isomorphisms `r` and `l`; see :meth:`Subobjects`;
|
|
379
|
+
|
|
380
|
+
.. NOTE::
|
|
381
|
+
|
|
382
|
+
- The usual definition of "subquotient"
|
|
383
|
+
(:wikipedia:`Subquotient`) does not involve the
|
|
384
|
+
lifting map `l`. This map is required in Sage's
|
|
385
|
+
context to make the definition constructive. It is
|
|
386
|
+
only used in computations and does not affect their
|
|
387
|
+
results. This is relatively harmless since the
|
|
388
|
+
category is a concrete category (i.e., its objects
|
|
389
|
+
are sets and its morphisms are set maps).
|
|
390
|
+
|
|
391
|
+
- In mathematics, especially in the context of
|
|
392
|
+
quotients, the retract map `r` is often referred to
|
|
393
|
+
as a *projection map* instead.
|
|
394
|
+
|
|
395
|
+
- Since `B'` is not specified explicitly, it is
|
|
396
|
+
possible to abuse the framework with situations
|
|
397
|
+
where `B'` is not quite a subobject and `r` not
|
|
398
|
+
quite a morphism, as long as the lifting and retract
|
|
399
|
+
maps can be used as above to compute all the
|
|
400
|
+
operations in `A`. Use at your own risk!
|
|
401
|
+
|
|
402
|
+
Assumptions:
|
|
403
|
+
|
|
404
|
+
- For any category ``As()``, ``As().Subquotients()`` is a
|
|
405
|
+
subcategory of ``As()``.
|
|
406
|
+
|
|
407
|
+
Example: a subquotient of a group is a group (e.g., a left
|
|
408
|
+
or right quotient of a group by a non-normal subgroup is
|
|
409
|
+
not in this category).
|
|
410
|
+
|
|
411
|
+
- This construction is covariant: if ``As()`` is a
|
|
412
|
+
subcategory of ``Bs()``, then ``As().Subquotients()`` is a
|
|
413
|
+
subcategory of ``Bs().Subquotients()``.
|
|
414
|
+
|
|
415
|
+
Example: if `A` is a subquotient of `B` in the category of
|
|
416
|
+
groups, then it is also a subquotient of `B` in the category
|
|
417
|
+
of monoids.
|
|
418
|
+
|
|
419
|
+
- If the user (or a program) calls ``As().Subquotients()``,
|
|
420
|
+
then it is assumed that subquotients are well defined in
|
|
421
|
+
this category. This is not checked, and probably never will
|
|
422
|
+
be. Note that, if a category ``As()`` does not specify
|
|
423
|
+
anything about its subquotients, then its subquotient
|
|
424
|
+
category looks like this::
|
|
425
|
+
|
|
426
|
+
sage: EuclideanDomains().Subquotients()
|
|
427
|
+
Join of Category of euclidean domains
|
|
428
|
+
and Category of subquotients of monoids
|
|
429
|
+
|
|
430
|
+
Interface: the ambient set `B` of `A` is given by
|
|
431
|
+
``A.ambient()``. The subset `B'` needs not be specified, so
|
|
432
|
+
the retract map is handled as a partial map from `B` to `A`.
|
|
433
|
+
|
|
434
|
+
The lifting and retract map are implemented
|
|
435
|
+
respectively as methods ``A.lift(a)`` and ``A.retract(b)``.
|
|
436
|
+
As a shorthand for the former, one can use alternatively
|
|
437
|
+
``a.lift()``::
|
|
438
|
+
|
|
439
|
+
sage: S = Semigroups().Subquotients().example(); S
|
|
440
|
+
An example of a (sub)quotient semigroup: a quotient of the left zero semigroup
|
|
441
|
+
sage: S.ambient()
|
|
442
|
+
An example of a semigroup: the left zero semigroup
|
|
443
|
+
sage: S(3).lift().parent()
|
|
444
|
+
An example of a semigroup: the left zero semigroup
|
|
445
|
+
sage: S(3) * S(1) == S.retract( S(3).lift() * S(1).lift() )
|
|
446
|
+
True
|
|
447
|
+
|
|
448
|
+
See ``S?`` for more.
|
|
449
|
+
|
|
450
|
+
.. TODO:: use a more interesting example, like `\ZZ/n\ZZ`.
|
|
451
|
+
|
|
452
|
+
.. SEEALSO::
|
|
453
|
+
|
|
454
|
+
- :meth:`Quotients`, :meth:`Subobjects`, :meth:`IsomorphicObjects`
|
|
455
|
+
- :class:`.subquotients.SubquotientsCategory`
|
|
456
|
+
- :class:`~.covariant_functorial_construction.RegressiveCovariantFunctorialConstruction`
|
|
457
|
+
|
|
458
|
+
TESTS::
|
|
459
|
+
|
|
460
|
+
sage: TestSuite(Sets().Subquotients()).run()
|
|
461
|
+
"""
|
|
462
|
+
return SubquotientsCategory.category_of(self)
|
|
463
|
+
|
|
464
|
+
@cached_method
|
|
465
|
+
def Quotients(self):
|
|
466
|
+
r"""
|
|
467
|
+
Return the full subcategory of the objects of ``self``
|
|
468
|
+
constructed as quotients.
|
|
469
|
+
|
|
470
|
+
Given a concrete category ``As()`` (i.e. a subcategory of
|
|
471
|
+
``Sets()``), ``As().Quotients()`` returns the category of
|
|
472
|
+
objects of ``As()`` endowed with a distinguished
|
|
473
|
+
description as quotient (in fact homomorphic image) of
|
|
474
|
+
some other object of ``As()``.
|
|
475
|
+
|
|
476
|
+
Implementing an object of ``As().Quotients()`` is done in
|
|
477
|
+
the same way as for ``As().Subquotients()``; namely by
|
|
478
|
+
providing an ambient space and a lift and a retract
|
|
479
|
+
map. See :meth:`Subquotients` for detailed instructions.
|
|
480
|
+
|
|
481
|
+
.. SEEALSO::
|
|
482
|
+
|
|
483
|
+
- :meth:`Subquotients` for background
|
|
484
|
+
- :class:`.quotients.QuotientsCategory`
|
|
485
|
+
- :class:`~.covariant_functorial_construction.RegressiveCovariantFunctorialConstruction`
|
|
486
|
+
|
|
487
|
+
EXAMPLES::
|
|
488
|
+
|
|
489
|
+
sage: C = Semigroups().Quotients(); C
|
|
490
|
+
Category of quotients of semigroups
|
|
491
|
+
sage: C.super_categories()
|
|
492
|
+
[Category of subquotients of semigroups, Category of quotients of sets]
|
|
493
|
+
sage: C.all_super_categories()
|
|
494
|
+
[Category of quotients of semigroups,
|
|
495
|
+
Category of subquotients of semigroups,
|
|
496
|
+
Category of semigroups,
|
|
497
|
+
Category of subquotients of magmas,
|
|
498
|
+
Category of magmas,
|
|
499
|
+
Category of quotients of sets,
|
|
500
|
+
Category of subquotients of sets,
|
|
501
|
+
Category of sets,
|
|
502
|
+
Category of sets with partial maps,
|
|
503
|
+
Category of objects]
|
|
504
|
+
|
|
505
|
+
The caller is responsible for checking that the given category
|
|
506
|
+
admits a well defined category of quotients::
|
|
507
|
+
|
|
508
|
+
sage: EuclideanDomains().Quotients()
|
|
509
|
+
Join of Category of euclidean domains
|
|
510
|
+
and Category of subquotients of monoids
|
|
511
|
+
and Category of quotients of semigroups
|
|
512
|
+
|
|
513
|
+
TESTS::
|
|
514
|
+
|
|
515
|
+
sage: TestSuite(C).run()
|
|
516
|
+
"""
|
|
517
|
+
return QuotientsCategory.category_of(self)
|
|
518
|
+
|
|
519
|
+
@cached_method
|
|
520
|
+
def Subobjects(self):
|
|
521
|
+
r"""
|
|
522
|
+
Return the full subcategory of the objects of ``self``
|
|
523
|
+
constructed as subobjects.
|
|
524
|
+
|
|
525
|
+
Given a concrete category ``As()`` (i.e. a subcategory of
|
|
526
|
+
``Sets()``), ``As().Subobjects()`` returns the category of
|
|
527
|
+
objects of ``As()`` endowed with a distinguished embedding
|
|
528
|
+
into some other object of ``As()``.
|
|
529
|
+
|
|
530
|
+
Implementing an object of ``As().Subobjects()`` is done in
|
|
531
|
+
the same way as for ``As().Subquotients()``; namely by
|
|
532
|
+
providing an ambient space and a lift and a retract
|
|
533
|
+
map. In the case of a trivial embedding, the two maps will
|
|
534
|
+
typically be identity maps that just change the parent of
|
|
535
|
+
their argument. See :meth:`Subquotients` for detailed
|
|
536
|
+
instructions.
|
|
537
|
+
|
|
538
|
+
.. SEEALSO::
|
|
539
|
+
|
|
540
|
+
- :meth:`Subquotients` for background
|
|
541
|
+
- :class:`.subobjects.SubobjectsCategory`
|
|
542
|
+
- :class:`~.covariant_functorial_construction.RegressiveCovariantFunctorialConstruction`
|
|
543
|
+
|
|
544
|
+
EXAMPLES::
|
|
545
|
+
|
|
546
|
+
sage: C = Sets().Subobjects(); C
|
|
547
|
+
Category of subobjects of sets
|
|
548
|
+
|
|
549
|
+
sage: C.super_categories()
|
|
550
|
+
[Category of subquotients of sets]
|
|
551
|
+
|
|
552
|
+
sage: C.all_super_categories()
|
|
553
|
+
[Category of subobjects of sets,
|
|
554
|
+
Category of subquotients of sets,
|
|
555
|
+
Category of sets,
|
|
556
|
+
Category of sets with partial maps,
|
|
557
|
+
Category of objects]
|
|
558
|
+
|
|
559
|
+
Unless something specific about subobjects is implemented for this
|
|
560
|
+
category, one actually gets an optimized super category::
|
|
561
|
+
|
|
562
|
+
sage: C = Semigroups().Subobjects(); C
|
|
563
|
+
Join of Category of subquotients of semigroups
|
|
564
|
+
and Category of subobjects of sets
|
|
565
|
+
|
|
566
|
+
The caller is responsible for checking that the given category
|
|
567
|
+
admits a well defined category of subobjects.
|
|
568
|
+
|
|
569
|
+
TESTS::
|
|
570
|
+
|
|
571
|
+
sage: Semigroups().Subobjects().is_subcategory(Semigroups().Subquotients())
|
|
572
|
+
True
|
|
573
|
+
sage: TestSuite(C).run()
|
|
574
|
+
"""
|
|
575
|
+
return SubobjectsCategory.category_of(self)
|
|
576
|
+
|
|
577
|
+
@cached_method
|
|
578
|
+
def IsomorphicObjects(self):
|
|
579
|
+
r"""
|
|
580
|
+
Return the full subcategory of the objects of ``self``
|
|
581
|
+
constructed by isomorphism.
|
|
582
|
+
|
|
583
|
+
Given a concrete category ``As()`` (i.e. a subcategory of
|
|
584
|
+
``Sets()``), ``As().IsomorphicObjects()`` returns the category of
|
|
585
|
+
objects of ``As()`` endowed with a distinguished description as
|
|
586
|
+
the image of some other object of ``As()`` by an isomorphism in
|
|
587
|
+
this category.
|
|
588
|
+
|
|
589
|
+
See :meth:`Subquotients` for background.
|
|
590
|
+
|
|
591
|
+
EXAMPLES:
|
|
592
|
+
|
|
593
|
+
In the following example, `A` is defined as the image by `x\mapsto
|
|
594
|
+
x^2` of the finite set `B = \{1,2,3\}`::
|
|
595
|
+
|
|
596
|
+
sage: A = FiniteEnumeratedSets().IsomorphicObjects().example(); A
|
|
597
|
+
The image by some isomorphism of An example of a finite enumerated set: {1,2,3}
|
|
598
|
+
|
|
599
|
+
Since `B` is a finite enumerated set, so is `A`::
|
|
600
|
+
|
|
601
|
+
sage: A in FiniteEnumeratedSets()
|
|
602
|
+
True
|
|
603
|
+
sage: A.cardinality()
|
|
604
|
+
3
|
|
605
|
+
sage: A.list()
|
|
606
|
+
[1, 4, 9]
|
|
607
|
+
|
|
608
|
+
The isomorphism from `B` to `A` is available as::
|
|
609
|
+
|
|
610
|
+
sage: A.retract(3)
|
|
611
|
+
9
|
|
612
|
+
|
|
613
|
+
and its inverse as::
|
|
614
|
+
|
|
615
|
+
sage: A.lift(9)
|
|
616
|
+
3
|
|
617
|
+
|
|
618
|
+
It often is natural to declare those morphisms as coercions so
|
|
619
|
+
that one can do ``A(b)`` and ``B(a)`` to go back and forth between
|
|
620
|
+
`A` and `B` (TODO: refer to a category example where the maps are
|
|
621
|
+
declared as a coercion). This is not done by default. Indeed, in
|
|
622
|
+
many cases one only wants to transport part of the structure of
|
|
623
|
+
`B` to `A`. Assume for example, that one wants to construct the
|
|
624
|
+
set of integers `B=ZZ`, endowed with ``max`` as addition, and
|
|
625
|
+
``+`` as multiplication instead of the usual ``+`` and ``*``. One
|
|
626
|
+
can construct `A` as isomorphic to `B` as an infinite enumerated
|
|
627
|
+
set. However `A` is *not* isomorphic to `B` as a ring; for
|
|
628
|
+
example, for `a\in A` and `a\in B`, the expressions `a+A(b)` and
|
|
629
|
+
`B(a)+b` give completely different results; hence we would not want
|
|
630
|
+
the expression `a+b` to be implicitly resolved to any one of above
|
|
631
|
+
two, as the coercion mechanism would do.
|
|
632
|
+
|
|
633
|
+
Coercions also cannot be used with facade parents (see
|
|
634
|
+
:class:`Sets.Facade`) like in the example above.
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
We now look at a category of isomorphic objects::
|
|
638
|
+
|
|
639
|
+
sage: C = Sets().IsomorphicObjects(); C
|
|
640
|
+
Category of isomorphic objects of sets
|
|
641
|
+
|
|
642
|
+
sage: C.super_categories()
|
|
643
|
+
[Category of subobjects of sets, Category of quotients of sets]
|
|
644
|
+
|
|
645
|
+
sage: C.all_super_categories()
|
|
646
|
+
[Category of isomorphic objects of sets,
|
|
647
|
+
Category of subobjects of sets,
|
|
648
|
+
Category of quotients of sets,
|
|
649
|
+
Category of subquotients of sets,
|
|
650
|
+
Category of sets,
|
|
651
|
+
Category of sets with partial maps,
|
|
652
|
+
Category of objects]
|
|
653
|
+
|
|
654
|
+
Unless something specific about isomorphic objects is implemented
|
|
655
|
+
for this category, one actually get an optimized super category::
|
|
656
|
+
|
|
657
|
+
sage: C = Semigroups().IsomorphicObjects(); C
|
|
658
|
+
Join of Category of quotients of semigroups
|
|
659
|
+
and Category of isomorphic objects of sets
|
|
660
|
+
|
|
661
|
+
.. SEEALSO::
|
|
662
|
+
|
|
663
|
+
- :meth:`Subquotients` for background
|
|
664
|
+
- :class:`.isomorphic_objects.IsomorphicObjectsCategory`
|
|
665
|
+
- :class:`~.covariant_functorial_construction.RegressiveCovariantFunctorialConstruction`
|
|
666
|
+
|
|
667
|
+
TESTS::
|
|
668
|
+
|
|
669
|
+
sage: TestSuite(Sets().IsomorphicObjects()).run()
|
|
670
|
+
"""
|
|
671
|
+
return IsomorphicObjectsCategory.category_of(self)
|
|
672
|
+
|
|
673
|
+
@cached_method
|
|
674
|
+
def Topological(self):
|
|
675
|
+
"""
|
|
676
|
+
Return the subcategory of the topological objects of ``self``.
|
|
677
|
+
|
|
678
|
+
TESTS::
|
|
679
|
+
|
|
680
|
+
sage: TestSuite(Sets().Topological()).run()
|
|
681
|
+
"""
|
|
682
|
+
from sage.categories.topological_spaces import TopologicalSpacesCategory
|
|
683
|
+
return TopologicalSpacesCategory.category_of(self)
|
|
684
|
+
|
|
685
|
+
@cached_method
|
|
686
|
+
def Metric(self):
|
|
687
|
+
"""
|
|
688
|
+
Return the subcategory of the metric objects of ``self``.
|
|
689
|
+
|
|
690
|
+
TESTS::
|
|
691
|
+
|
|
692
|
+
sage: TestSuite(Sets().Metric()).run()
|
|
693
|
+
"""
|
|
694
|
+
from sage.categories.metric_spaces import MetricSpacesCategory
|
|
695
|
+
return MetricSpacesCategory.category_of(self)
|
|
696
|
+
|
|
697
|
+
@cached_method
|
|
698
|
+
def Algebras(self, base_ring):
|
|
699
|
+
"""
|
|
700
|
+
Return the category of objects constructed as algebras of
|
|
701
|
+
objects of ``self`` over ``base_ring``.
|
|
702
|
+
|
|
703
|
+
INPUT:
|
|
704
|
+
|
|
705
|
+
- ``base_ring`` -- a ring
|
|
706
|
+
|
|
707
|
+
See :meth:`Sets.ParentMethods.algebra` for the precise
|
|
708
|
+
meaning in Sage of the *algebra of an object*.
|
|
709
|
+
|
|
710
|
+
EXAMPLES::
|
|
711
|
+
|
|
712
|
+
sage: Monoids().Algebras(QQ)
|
|
713
|
+
Category of monoid algebras over Rational Field
|
|
714
|
+
|
|
715
|
+
sage: Groups().Algebras(QQ)
|
|
716
|
+
Category of group algebras over Rational Field
|
|
717
|
+
|
|
718
|
+
sage: AdditiveMagmas().AdditiveAssociative().Algebras(QQ)
|
|
719
|
+
Category of additive semigroup algebras over Rational Field
|
|
720
|
+
|
|
721
|
+
sage: Monoids().Algebras(Rings())
|
|
722
|
+
Category of monoid algebras over Category of rings
|
|
723
|
+
|
|
724
|
+
.. SEEALSO::
|
|
725
|
+
|
|
726
|
+
- :class:`.algebra_functor.AlgebrasCategory`
|
|
727
|
+
- :class:`~.covariant_functorial_construction.CovariantFunctorialConstruction`
|
|
728
|
+
|
|
729
|
+
TESTS::
|
|
730
|
+
|
|
731
|
+
sage: TestSuite(Groups().Finite().Algebras(QQ)).run()
|
|
732
|
+
"""
|
|
733
|
+
from sage.categories.rings import Rings
|
|
734
|
+
assert base_ring in Rings() or (isinstance(base_ring, Category)
|
|
735
|
+
and base_ring.is_subcategory(Rings()))
|
|
736
|
+
return AlgebrasCategory.category_of(self, base_ring)
|
|
737
|
+
|
|
738
|
+
@cached_method
|
|
739
|
+
def Finite(self):
|
|
740
|
+
"""
|
|
741
|
+
Return the full subcategory of the finite objects of ``self``.
|
|
742
|
+
|
|
743
|
+
EXAMPLES::
|
|
744
|
+
|
|
745
|
+
sage: Sets().Finite()
|
|
746
|
+
Category of finite sets
|
|
747
|
+
sage: Rings().Finite()
|
|
748
|
+
Category of finite rings
|
|
749
|
+
|
|
750
|
+
TESTS::
|
|
751
|
+
|
|
752
|
+
sage: TestSuite(Sets().Finite()).run()
|
|
753
|
+
sage: Rings().Finite.__module__
|
|
754
|
+
'sage.categories.sets_cat'
|
|
755
|
+
"""
|
|
756
|
+
return self._with_axiom('Finite')
|
|
757
|
+
|
|
758
|
+
@cached_method
|
|
759
|
+
def Infinite(self):
|
|
760
|
+
"""
|
|
761
|
+
Return the full subcategory of the infinite objects of ``self``.
|
|
762
|
+
|
|
763
|
+
EXAMPLES::
|
|
764
|
+
|
|
765
|
+
sage: Sets().Infinite()
|
|
766
|
+
Category of infinite sets
|
|
767
|
+
sage: Rings().Infinite()
|
|
768
|
+
Category of infinite rings
|
|
769
|
+
|
|
770
|
+
TESTS::
|
|
771
|
+
|
|
772
|
+
sage: TestSuite(Sets().Infinite()).run()
|
|
773
|
+
sage: Rings().Infinite.__module__
|
|
774
|
+
'sage.categories.sets_cat'
|
|
775
|
+
"""
|
|
776
|
+
return self._with_axiom('Infinite')
|
|
777
|
+
|
|
778
|
+
@cached_method
|
|
779
|
+
def Enumerated(self):
|
|
780
|
+
"""
|
|
781
|
+
Return the full subcategory of the enumerated objects of ``self``.
|
|
782
|
+
|
|
783
|
+
An enumerated object can be iterated to get its elements.
|
|
784
|
+
|
|
785
|
+
EXAMPLES::
|
|
786
|
+
|
|
787
|
+
sage: Sets().Enumerated()
|
|
788
|
+
Category of enumerated sets
|
|
789
|
+
sage: Rings().Finite().Enumerated()
|
|
790
|
+
Category of finite enumerated rings
|
|
791
|
+
sage: Rings().Infinite().Enumerated()
|
|
792
|
+
Category of infinite enumerated rings
|
|
793
|
+
|
|
794
|
+
TESTS::
|
|
795
|
+
|
|
796
|
+
sage: TestSuite(Sets().Enumerated()).run()
|
|
797
|
+
sage: Rings().Enumerated.__module__
|
|
798
|
+
'sage.categories.sets_cat'
|
|
799
|
+
"""
|
|
800
|
+
return self._with_axiom('Enumerated')
|
|
801
|
+
|
|
802
|
+
def Facade(self):
|
|
803
|
+
r"""
|
|
804
|
+
Return the full subcategory of the facade objects of ``self``.
|
|
805
|
+
|
|
806
|
+
.. _facade-sets:
|
|
807
|
+
|
|
808
|
+
.. RUBRIC:: What is a facade set?
|
|
809
|
+
|
|
810
|
+
Recall that, in Sage, :ref:`sets are modelled by *parents*
|
|
811
|
+
<category-primer-parents-elements-categories>`, and their
|
|
812
|
+
elements know which distinguished set they belong to. For
|
|
813
|
+
example, the ring of integers `\ZZ` is modelled by the
|
|
814
|
+
parent :obj:`ZZ`, and integers know that they belong to
|
|
815
|
+
this set::
|
|
816
|
+
|
|
817
|
+
sage: ZZ
|
|
818
|
+
Integer Ring
|
|
819
|
+
sage: 42.parent()
|
|
820
|
+
Integer Ring
|
|
821
|
+
|
|
822
|
+
Sometimes, it is convenient to represent the elements of a
|
|
823
|
+
parent ``P`` by elements of some other parent. For
|
|
824
|
+
example, the elements of the set of prime numbers are
|
|
825
|
+
represented by plain integers::
|
|
826
|
+
|
|
827
|
+
sage: Primes()
|
|
828
|
+
Set of all prime numbers: 2, 3, 5, 7, ...
|
|
829
|
+
sage: p = Primes().an_element(); p
|
|
830
|
+
43
|
|
831
|
+
sage: p.parent()
|
|
832
|
+
Integer Ring
|
|
833
|
+
|
|
834
|
+
In this case, ``P`` is called a *facade set*.
|
|
835
|
+
|
|
836
|
+
This feature is advertised through the category of `P`::
|
|
837
|
+
|
|
838
|
+
sage: Primes().category()
|
|
839
|
+
Category of facade infinite enumerated sets
|
|
840
|
+
sage: Sets().Facade()
|
|
841
|
+
Category of facade sets
|
|
842
|
+
|
|
843
|
+
Typical use cases include modeling a subset of an existing
|
|
844
|
+
parent::
|
|
845
|
+
|
|
846
|
+
sage: Set([4,6,9]) # random
|
|
847
|
+
{4, 6, 9}
|
|
848
|
+
sage: Sets().Facade().example()
|
|
849
|
+
An example of facade set: the monoid of positive integers
|
|
850
|
+
|
|
851
|
+
or the union of several parents::
|
|
852
|
+
|
|
853
|
+
sage: Sets().Facade().example("union")
|
|
854
|
+
An example of a facade set: the integers completed by +-infinity
|
|
855
|
+
|
|
856
|
+
or endowing an existing parent with more (or less!)
|
|
857
|
+
structure::
|
|
858
|
+
|
|
859
|
+
sage: Posets().example("facade")
|
|
860
|
+
An example of a facade poset: the positive integers ordered by divisibility
|
|
861
|
+
|
|
862
|
+
Let us investigate in detail a close variant of this last
|
|
863
|
+
example: let `P` be set of divisors of `12` partially
|
|
864
|
+
ordered by divisibility. There are two options for
|
|
865
|
+
representing its elements:
|
|
866
|
+
|
|
867
|
+
1. as plain integers::
|
|
868
|
+
|
|
869
|
+
sage: P = Poset((divisors(12), attrcall("divides")), facade=True) # needs sage.graphs
|
|
870
|
+
|
|
871
|
+
2. as integers, modified to be aware that their parent is `P`::
|
|
872
|
+
|
|
873
|
+
sage: Q = Poset((divisors(12), attrcall("divides")), facade=False) # needs sage.graphs
|
|
874
|
+
|
|
875
|
+
The advantage of option 1. is that one needs not do
|
|
876
|
+
conversions back and forth between `P` and `\ZZ`. The
|
|
877
|
+
disadvantage is that this introduces an ambiguity when
|
|
878
|
+
writing `2 < 3`: does this compare `2` and `3` w.r.t. the
|
|
879
|
+
natural order on integers or w.r.t. divisibility?::
|
|
880
|
+
|
|
881
|
+
sage: 2 < 3
|
|
882
|
+
True
|
|
883
|
+
|
|
884
|
+
To raise this ambiguity, one needs to explicitly specify
|
|
885
|
+
the underlying poset as in `2 <_P 3`::
|
|
886
|
+
|
|
887
|
+
sage: P = Posets().example("facade")
|
|
888
|
+
sage: P.lt(2,3)
|
|
889
|
+
False
|
|
890
|
+
|
|
891
|
+
On the other hand, with option 2. and once constructed,
|
|
892
|
+
the elements know unambiguously how to compare
|
|
893
|
+
themselves::
|
|
894
|
+
|
|
895
|
+
sage: Q(2) < Q(3) # needs sage.graphs
|
|
896
|
+
False
|
|
897
|
+
sage: Q(2) < Q(6) # needs sage.graphs
|
|
898
|
+
True
|
|
899
|
+
|
|
900
|
+
Beware that ``P(2)`` is still the integer `2`. Therefore
|
|
901
|
+
``P(2) < P(3)`` still compares `2` and `3` as integers!::
|
|
902
|
+
|
|
903
|
+
sage: P(2) < P(3)
|
|
904
|
+
True
|
|
905
|
+
|
|
906
|
+
In short `P` being a facade parent is one of the programmatic
|
|
907
|
+
counterparts (with e.g. coercions) of the usual mathematical idiom:
|
|
908
|
+
"for ease of notation, we identify an element of `P` with the
|
|
909
|
+
corresponding integer". Too many identifications lead to
|
|
910
|
+
confusion; the lack thereof leads to heavy, if not obfuscated,
|
|
911
|
+
notations. Finding the right balance is an art, and even though
|
|
912
|
+
there are common guidelines, it is ultimately up to the writer to
|
|
913
|
+
choose which identifications to do. This is no different in code.
|
|
914
|
+
|
|
915
|
+
.. SEEALSO::
|
|
916
|
+
|
|
917
|
+
The following examples illustrate various ways to
|
|
918
|
+
implement subsets like the set of prime numbers; look
|
|
919
|
+
at their code for details::
|
|
920
|
+
|
|
921
|
+
sage: Sets().example("facade")
|
|
922
|
+
Set of prime numbers (facade implementation)
|
|
923
|
+
sage: Sets().example("inherits")
|
|
924
|
+
Set of prime numbers
|
|
925
|
+
sage: Sets().example("wrapper")
|
|
926
|
+
Set of prime numbers (wrapper implementation)
|
|
927
|
+
|
|
928
|
+
.. RUBRIC:: Specifications
|
|
929
|
+
|
|
930
|
+
A parent which is a facade must either:
|
|
931
|
+
|
|
932
|
+
- call :meth:`Parent.__init__` using the ``facade`` parameter to
|
|
933
|
+
specify a parent, or tuple thereof.
|
|
934
|
+
- overload the method :meth:`~Sets.Facade.ParentMethods.facade_for`.
|
|
935
|
+
|
|
936
|
+
.. NOTE::
|
|
937
|
+
|
|
938
|
+
The concept of facade parents was originally introduced
|
|
939
|
+
in the computer algebra system MuPAD.
|
|
940
|
+
|
|
941
|
+
TESTS:
|
|
942
|
+
|
|
943
|
+
Check that multiple categories initialisation
|
|
944
|
+
works (:issue:`13801`)::
|
|
945
|
+
|
|
946
|
+
sage: class A(Parent):
|
|
947
|
+
....: def __init__(self):
|
|
948
|
+
....: Parent.__init__(self, category=(FiniteEnumeratedSets(),Monoids()), facade=True)
|
|
949
|
+
sage: a = A()
|
|
950
|
+
|
|
951
|
+
sage: Posets().Facade()
|
|
952
|
+
Category of facade posets
|
|
953
|
+
sage: Posets().Facade().Finite() is Posets().Finite().Facade()
|
|
954
|
+
True
|
|
955
|
+
"""
|
|
956
|
+
return self._with_axiom('Facade')
|
|
957
|
+
|
|
958
|
+
class ParentMethods:
|
|
959
|
+
# TODO: simplify the _element_constructor_ definition logic
|
|
960
|
+
# TODO: find a nicer mantra for conditionally defined methods
|
|
961
|
+
@lazy_attribute
|
|
962
|
+
def _element_constructor_(self):
|
|
963
|
+
r"""
|
|
964
|
+
TESTS::
|
|
965
|
+
|
|
966
|
+
sage: S = Sets().example()
|
|
967
|
+
sage: S._element_constructor_(17)
|
|
968
|
+
17
|
|
969
|
+
sage: S(17) # indirect doctest
|
|
970
|
+
17
|
|
971
|
+
|
|
972
|
+
sage: A = FreeModule(QQ, 3) # needs sage.modules
|
|
973
|
+
sage: A.element_class # needs sage.modules
|
|
974
|
+
<class 'sage.modules.vector_rational_dense.Vector_rational_dense'>
|
|
975
|
+
sage: A._element_constructor_ # needs sage.modules
|
|
976
|
+
<bound method FreeModule_ambient_field._element_constructor_
|
|
977
|
+
of Vector space of dimension 3 over Rational Field>
|
|
978
|
+
|
|
979
|
+
sage: B = SymmetricGroup(3).algebra(ZZ) # needs sage.combinat sage.groups sage.modules
|
|
980
|
+
sage: B.element_class # needs sage.combinat sage.groups sage.modules
|
|
981
|
+
<...SymmetricGroupAlgebra_n_with_category.element_class'>
|
|
982
|
+
sage: B._element_constructor_ # needs sage.combinat sage.groups sage.modules
|
|
983
|
+
<bound method SymmetricGroupAlgebra_n._element_constructor_
|
|
984
|
+
of Symmetric group algebra of order 3 over Integer Ring>
|
|
985
|
+
"""
|
|
986
|
+
if hasattr(self, "element_class"):
|
|
987
|
+
return self._element_constructor_from_element_class
|
|
988
|
+
else:
|
|
989
|
+
return NotImplemented
|
|
990
|
+
|
|
991
|
+
def _element_constructor_from_element_class(self, *args, **keywords):
|
|
992
|
+
"""
|
|
993
|
+
The default constructor for elements of this parent ``self``.
|
|
994
|
+
|
|
995
|
+
Among other things, it is called upon ``self(data)`` when
|
|
996
|
+
the coercion model did not find a way to coerce ``data`` into
|
|
997
|
+
this parent.
|
|
998
|
+
|
|
999
|
+
This default implementation for
|
|
1000
|
+
:meth:`_element_constructor_` calls the constructor of the
|
|
1001
|
+
element class, passing ``self`` as first argument.
|
|
1002
|
+
|
|
1003
|
+
EXAMPLES::
|
|
1004
|
+
|
|
1005
|
+
sage: S = Sets().example("inherits")
|
|
1006
|
+
sage: s = S._element_constructor_from_element_class(17); s
|
|
1007
|
+
17
|
|
1008
|
+
sage: type(s)
|
|
1009
|
+
<class 'sage.categories.examples.sets_cat.PrimeNumbers_Inherits_with_category.element_class'>
|
|
1010
|
+
"""
|
|
1011
|
+
return self.element_class(self, *args, **keywords)
|
|
1012
|
+
|
|
1013
|
+
def is_parent_of(self, element):
|
|
1014
|
+
"""
|
|
1015
|
+
Return whether ``self`` is the parent of ``element``.
|
|
1016
|
+
|
|
1017
|
+
INPUT:
|
|
1018
|
+
|
|
1019
|
+
- ``element`` -- any object
|
|
1020
|
+
|
|
1021
|
+
EXAMPLES::
|
|
1022
|
+
|
|
1023
|
+
sage: S = ZZ
|
|
1024
|
+
sage: S.is_parent_of(1)
|
|
1025
|
+
True
|
|
1026
|
+
sage: S.is_parent_of(2/1)
|
|
1027
|
+
False
|
|
1028
|
+
|
|
1029
|
+
This method differs from :meth:`__contains__` because it
|
|
1030
|
+
does not attempt any coercion::
|
|
1031
|
+
|
|
1032
|
+
sage: 2/1 in S, S.is_parent_of(2/1)
|
|
1033
|
+
(True, False)
|
|
1034
|
+
sage: int(1) in S, S.is_parent_of(int(1))
|
|
1035
|
+
(True, False)
|
|
1036
|
+
"""
|
|
1037
|
+
from sage.structure.element import parent
|
|
1038
|
+
return parent(element) == self
|
|
1039
|
+
|
|
1040
|
+
@abstract_method
|
|
1041
|
+
def __contains__(self, x):
|
|
1042
|
+
"""
|
|
1043
|
+
Test whether the set ``self`` contains the object ``x``.
|
|
1044
|
+
|
|
1045
|
+
All parents in the category ``Sets()`` should implement this method.
|
|
1046
|
+
|
|
1047
|
+
EXAMPLES::
|
|
1048
|
+
|
|
1049
|
+
sage: P = Sets().example(); P
|
|
1050
|
+
Set of prime numbers (basic implementation)
|
|
1051
|
+
sage: 12 in P
|
|
1052
|
+
False
|
|
1053
|
+
sage: P(5) in P
|
|
1054
|
+
True
|
|
1055
|
+
"""
|
|
1056
|
+
|
|
1057
|
+
@cached_method
|
|
1058
|
+
def an_element(self):
|
|
1059
|
+
r"""
|
|
1060
|
+
Return a (preferably typical) element of this parent.
|
|
1061
|
+
|
|
1062
|
+
This is used both for illustration and testing purposes. If the
|
|
1063
|
+
set ``self`` is empty, :meth:`an_element` should raise the exception
|
|
1064
|
+
:exc:`EmptySetError`.
|
|
1065
|
+
|
|
1066
|
+
This default implementation calls :meth:`_an_element_` and
|
|
1067
|
+
caches the result. Any parent should implement either
|
|
1068
|
+
:meth:`an_element` or :meth:`_an_element_`.
|
|
1069
|
+
|
|
1070
|
+
EXAMPLES::
|
|
1071
|
+
|
|
1072
|
+
sage: CDF.an_element() # needs sage.rings.complex_double
|
|
1073
|
+
1.0*I
|
|
1074
|
+
sage: ZZ[['t']].an_element()
|
|
1075
|
+
t
|
|
1076
|
+
"""
|
|
1077
|
+
return self._an_element_()
|
|
1078
|
+
|
|
1079
|
+
def _test_an_element(self, **options):
|
|
1080
|
+
"""
|
|
1081
|
+
Run generic tests on the method :meth:`.an_element`.
|
|
1082
|
+
|
|
1083
|
+
See also: :class:`TestSuite`.
|
|
1084
|
+
|
|
1085
|
+
EXAMPLES::
|
|
1086
|
+
|
|
1087
|
+
sage: C = Sets().example()
|
|
1088
|
+
sage: C._test_an_element()
|
|
1089
|
+
|
|
1090
|
+
Let us now write a broken :meth:`.an_element` method::
|
|
1091
|
+
|
|
1092
|
+
sage: from sage.categories.examples.sets_cat import PrimeNumbers
|
|
1093
|
+
sage: class CCls(PrimeNumbers):
|
|
1094
|
+
....: def an_element(self):
|
|
1095
|
+
....: return 18
|
|
1096
|
+
sage: CC = CCls()
|
|
1097
|
+
sage: CC._test_an_element()
|
|
1098
|
+
Traceback (most recent call last):
|
|
1099
|
+
...
|
|
1100
|
+
AssertionError: self.an_element() is not in self
|
|
1101
|
+
|
|
1102
|
+
TESTS::
|
|
1103
|
+
|
|
1104
|
+
sage: FiniteEnumeratedSet([])._test_an_element()
|
|
1105
|
+
"""
|
|
1106
|
+
tester = self._tester(**options)
|
|
1107
|
+
try:
|
|
1108
|
+
an_element = self.an_element()
|
|
1109
|
+
except EmptySetError:
|
|
1110
|
+
return
|
|
1111
|
+
tester.assertIn(an_element, self, "self.an_element() is not in self")
|
|
1112
|
+
# tester.assertTrue(self.is_parent_of(an_element), "self is not the parent of self.an_element()")
|
|
1113
|
+
# tester.assertEqual(self(an_element), an_element, "element construction is not idempotent")
|
|
1114
|
+
if self.is_parent_of(an_element):
|
|
1115
|
+
tester.assertEqual(self(an_element), an_element, "element construction is not idempotent")
|
|
1116
|
+
else: # Allows self(an_element) to fails for facade parent.
|
|
1117
|
+
try:
|
|
1118
|
+
rebuilt_element = self(an_element)
|
|
1119
|
+
except NotImplementedError:
|
|
1120
|
+
tester.info("\n The set doesn't seems to implement __call__; skipping test of construction idempotency")
|
|
1121
|
+
else:
|
|
1122
|
+
tester.assertEqual(rebuilt_element, an_element, "element construction is not idempotent")
|
|
1123
|
+
|
|
1124
|
+
def _test_elements(self, tester=None, **options):
|
|
1125
|
+
"""
|
|
1126
|
+
Run generic tests on element(s) of ``self``.
|
|
1127
|
+
|
|
1128
|
+
See also: :class:`TestSuite`.
|
|
1129
|
+
|
|
1130
|
+
EXAMPLES::
|
|
1131
|
+
|
|
1132
|
+
sage: C = Sets().example()
|
|
1133
|
+
sage: C._test_elements(verbose = True)
|
|
1134
|
+
<BLANKLINE>
|
|
1135
|
+
Running the test suite of self.an_element()
|
|
1136
|
+
running ._test_category() . . . pass
|
|
1137
|
+
running ._test_eq() . . . pass
|
|
1138
|
+
running ._test_new() . . . pass
|
|
1139
|
+
running ._test_nonzero_equal() . . . pass
|
|
1140
|
+
running ._test_not_implemented_methods() . . . pass
|
|
1141
|
+
running ._test_pickling() . . . pass
|
|
1142
|
+
<BLANKLINE>
|
|
1143
|
+
|
|
1144
|
+
Debugging tip: in case of failure of this test, run instead::
|
|
1145
|
+
|
|
1146
|
+
sage: TestSuite(C.an_element()).run()
|
|
1147
|
+
|
|
1148
|
+
Let us now implement a parent whose elements cannot be pickled::
|
|
1149
|
+
|
|
1150
|
+
sage: from sage.categories.examples.sets_cat import PrimeNumbers
|
|
1151
|
+
sage: class Bla(SageObject): pass
|
|
1152
|
+
sage: class CCls(PrimeNumbers):
|
|
1153
|
+
....: def an_element(self):
|
|
1154
|
+
....: return Bla()
|
|
1155
|
+
sage: CC = CCls()
|
|
1156
|
+
sage: CC._test_elements()
|
|
1157
|
+
Failure in _test_pickling:
|
|
1158
|
+
...
|
|
1159
|
+
The following tests failed: _test_pickling
|
|
1160
|
+
"""
|
|
1161
|
+
# TODO: add native support for nested test suites to TestSuite
|
|
1162
|
+
|
|
1163
|
+
# The intention is to raise an exception only if this is
|
|
1164
|
+
# run as a sub-testsuite of a larger testsuite.
|
|
1165
|
+
is_sub_testsuite = (tester is not None)
|
|
1166
|
+
tester = self._tester(tester=tester, **options)
|
|
1167
|
+
# Or do we want to run the test on some_elements?
|
|
1168
|
+
try:
|
|
1169
|
+
an_element = self.an_element()
|
|
1170
|
+
except EmptySetError:
|
|
1171
|
+
return
|
|
1172
|
+
tester.info("\n Running the test suite of self.an_element()")
|
|
1173
|
+
TestSuite(an_element).run(verbose=tester._verbose,
|
|
1174
|
+
prefix=tester._prefix + " ",
|
|
1175
|
+
raise_on_failure=is_sub_testsuite)
|
|
1176
|
+
tester.info(tester._prefix + " ", newline=False)
|
|
1177
|
+
|
|
1178
|
+
def _test_elements_eq_reflexive(self, **options):
|
|
1179
|
+
"""
|
|
1180
|
+
Run generic tests on the equality of elements.
|
|
1181
|
+
|
|
1182
|
+
Test that ``==`` is reflexive.
|
|
1183
|
+
|
|
1184
|
+
See also: :class:`TestSuite`.
|
|
1185
|
+
|
|
1186
|
+
EXAMPLES::
|
|
1187
|
+
|
|
1188
|
+
sage: C = Sets().example()
|
|
1189
|
+
sage: C._test_elements_eq_reflexive()
|
|
1190
|
+
|
|
1191
|
+
We try a non-reflexive equality::
|
|
1192
|
+
|
|
1193
|
+
sage: P = Sets().example("wrapper")
|
|
1194
|
+
sage: P._test_elements_eq_reflexive() # needs sage.libs.pari
|
|
1195
|
+
sage: eq = P.element_class.__eq__
|
|
1196
|
+
|
|
1197
|
+
sage: P.element_class.__eq__ = (lambda x, y:
|
|
1198
|
+
....: False if eq(x, P(47)) and eq(y, P(47)) else eq(x, y))
|
|
1199
|
+
sage: P._test_elements_eq_reflexive() # needs sage.libs.pari
|
|
1200
|
+
Traceback (most recent call last):
|
|
1201
|
+
...
|
|
1202
|
+
AssertionError: 47 != 47
|
|
1203
|
+
|
|
1204
|
+
We restore ``P.element_class`` in a proper state for further tests::
|
|
1205
|
+
|
|
1206
|
+
sage: P.element_class.__eq__ = eq
|
|
1207
|
+
"""
|
|
1208
|
+
tester = self._tester(**options)
|
|
1209
|
+
S = list(tester.some_elements()) + [None, 0]
|
|
1210
|
+
for x in S:
|
|
1211
|
+
tester.assertEqual(x, x)
|
|
1212
|
+
|
|
1213
|
+
def _test_elements_eq_symmetric(self, **options):
|
|
1214
|
+
"""
|
|
1215
|
+
Run generic tests on the equality of elements.
|
|
1216
|
+
|
|
1217
|
+
This tests that ``==`` is symmetric.
|
|
1218
|
+
|
|
1219
|
+
See also: :class:`TestSuite`.
|
|
1220
|
+
|
|
1221
|
+
EXAMPLES::
|
|
1222
|
+
|
|
1223
|
+
sage: C = Sets().example()
|
|
1224
|
+
sage: C._test_elements_eq_symmetric()
|
|
1225
|
+
|
|
1226
|
+
We test a non symmetric equality::
|
|
1227
|
+
|
|
1228
|
+
sage: P = Sets().example("wrapper")
|
|
1229
|
+
sage: P._test_elements_eq_symmetric() # needs sage.libs.pari
|
|
1230
|
+
sage: eq = P.element_class.__eq__
|
|
1231
|
+
|
|
1232
|
+
sage: def non_sym_eq(x, y):
|
|
1233
|
+
....: if not y in P: return False
|
|
1234
|
+
....: elif eq(x, P(47)) and eq(y, P(53)): return True
|
|
1235
|
+
....: else: return eq(x, y)
|
|
1236
|
+
sage: P.element_class.__eq__ = non_sym_eq
|
|
1237
|
+
sage: P._test_elements_eq_symmetric() # needs sage.libs.pari
|
|
1238
|
+
Traceback (most recent call last):
|
|
1239
|
+
...
|
|
1240
|
+
AssertionError: non symmetric equality: 47 == 53 but 53 != 47
|
|
1241
|
+
|
|
1242
|
+
We restore ``P.element_class`` in a proper state for further tests::
|
|
1243
|
+
|
|
1244
|
+
sage: P.element_class.__eq__ = eq
|
|
1245
|
+
"""
|
|
1246
|
+
tester = self._tester(**options)
|
|
1247
|
+
S = list(tester.some_elements()) + [None, 0]
|
|
1248
|
+
from sage.misc.misc import some_tuples
|
|
1249
|
+
for x, y in some_tuples(S, 2, tester._max_runs):
|
|
1250
|
+
tester.assertEqual(x == y, y == x,
|
|
1251
|
+
LazyFormat("non symmetric equality: %s but %s") % (
|
|
1252
|
+
print_compare(x, y), print_compare(y, x)))
|
|
1253
|
+
|
|
1254
|
+
def _test_elements_eq_transitive(self, **options):
|
|
1255
|
+
"""
|
|
1256
|
+
Run generic tests on the equality of elements.
|
|
1257
|
+
|
|
1258
|
+
Test that ``==`` is transitive.
|
|
1259
|
+
|
|
1260
|
+
See also: :class:`TestSuite`.
|
|
1261
|
+
|
|
1262
|
+
EXAMPLES::
|
|
1263
|
+
|
|
1264
|
+
sage: C = Sets().example()
|
|
1265
|
+
sage: C._test_elements_eq_transitive()
|
|
1266
|
+
|
|
1267
|
+
We test a non transitive equality::
|
|
1268
|
+
|
|
1269
|
+
sage: R = Zp(3) # needs sage.rings.padics
|
|
1270
|
+
sage: test = raw_getattr(Sets().ParentMethods, "_test_elements_eq_transitive")
|
|
1271
|
+
sage: test(R, elements=[R(3,2), R(3,1), R(0)]) # needs sage.rings.padics
|
|
1272
|
+
Traceback (most recent call last):
|
|
1273
|
+
...
|
|
1274
|
+
AssertionError: non transitive equality:
|
|
1275
|
+
3 + O(3^2) == O(3) and O(3) == 0 but 3 + O(3^2) != 0
|
|
1276
|
+
"""
|
|
1277
|
+
tester = self._tester(**options)
|
|
1278
|
+
S = list(tester.some_elements())
|
|
1279
|
+
n = max(tester._max_runs, 8)
|
|
1280
|
+
if (len(S)+2)**3 <= n:
|
|
1281
|
+
S = list(S) + [None, 0]
|
|
1282
|
+
else:
|
|
1283
|
+
from random import sample
|
|
1284
|
+
from sage.rings.integer import Integer
|
|
1285
|
+
S = sample(S, Integer(n).nth_root(3,truncate_mode=1)[0] - 2) + [None, 0]
|
|
1286
|
+
|
|
1287
|
+
for x in S:
|
|
1288
|
+
for y in S:
|
|
1289
|
+
if not x == y:
|
|
1290
|
+
continue
|
|
1291
|
+
for z in S:
|
|
1292
|
+
if not y == z:
|
|
1293
|
+
continue
|
|
1294
|
+
tester.assertEqual(x, z,
|
|
1295
|
+
LazyFormat("non transitive equality:\n"
|
|
1296
|
+
"%s and %s but %s") % (
|
|
1297
|
+
print_compare(x, y),
|
|
1298
|
+
print_compare(y, z),
|
|
1299
|
+
print_compare(x, z)))
|
|
1300
|
+
|
|
1301
|
+
def _test_elements_neq(self, **options):
|
|
1302
|
+
"""
|
|
1303
|
+
Run generic tests on the equality of elements.
|
|
1304
|
+
|
|
1305
|
+
Test that ``==`` and ``!=`` are consistent.
|
|
1306
|
+
|
|
1307
|
+
See also: :class:`TestSuite`.
|
|
1308
|
+
|
|
1309
|
+
EXAMPLES::
|
|
1310
|
+
|
|
1311
|
+
sage: C = Sets().example()
|
|
1312
|
+
sage: C._test_elements_neq()
|
|
1313
|
+
|
|
1314
|
+
We try a broken inequality::
|
|
1315
|
+
|
|
1316
|
+
sage: P = Sets().example("wrapper")
|
|
1317
|
+
sage: P._test_elements_neq() # needs sage.libs.pari
|
|
1318
|
+
sage: ne = P.element_class.__ne__
|
|
1319
|
+
sage: eq = P.element_class.__eq__
|
|
1320
|
+
|
|
1321
|
+
sage: P.element_class.__ne__ = lambda x, y: False
|
|
1322
|
+
sage: P._test_elements_neq() # needs sage.libs.pari
|
|
1323
|
+
Traceback (most recent call last):
|
|
1324
|
+
...
|
|
1325
|
+
AssertionError: __eq__ and __ne__ inconsistency:
|
|
1326
|
+
47 == 53 returns False but 47 != 53 returns False
|
|
1327
|
+
|
|
1328
|
+
sage: P.element_class.__ne__ = lambda x, y: not(x == y)
|
|
1329
|
+
|
|
1330
|
+
We restore ``P.element_class`` in a proper state for further tests::
|
|
1331
|
+
|
|
1332
|
+
sage: P.element_class.__ne__ = ne
|
|
1333
|
+
sage: P.element_class.__eq__ = eq
|
|
1334
|
+
"""
|
|
1335
|
+
tester = self._tester(**options)
|
|
1336
|
+
S = list(tester.some_elements()) + [None, 0]
|
|
1337
|
+
|
|
1338
|
+
from sage.misc.misc import some_tuples
|
|
1339
|
+
for x,y in some_tuples(S, 2, tester._max_runs):
|
|
1340
|
+
tester.assertNotEqual(x == y, x != y,
|
|
1341
|
+
LazyFormat("__eq__ and __ne__ inconsistency:\n"
|
|
1342
|
+
" %s == %s returns %s but %s != %s returns %s") % (
|
|
1343
|
+
x, y, (x == y), x, y, (x != y)))
|
|
1344
|
+
|
|
1345
|
+
def some_elements(self):
|
|
1346
|
+
"""
|
|
1347
|
+
Return a list (or iterable) of elements of ``self``.
|
|
1348
|
+
|
|
1349
|
+
This is typically used for running generic tests
|
|
1350
|
+
(see :class:`TestSuite`).
|
|
1351
|
+
|
|
1352
|
+
This default implementation calls :meth:`.an_element`.
|
|
1353
|
+
|
|
1354
|
+
EXAMPLES::
|
|
1355
|
+
|
|
1356
|
+
sage: S = Sets().example(); S
|
|
1357
|
+
Set of prime numbers (basic implementation)
|
|
1358
|
+
sage: S.an_element()
|
|
1359
|
+
47
|
|
1360
|
+
sage: S.some_elements()
|
|
1361
|
+
[47]
|
|
1362
|
+
sage: S = Set([])
|
|
1363
|
+
sage: list(S.some_elements())
|
|
1364
|
+
[]
|
|
1365
|
+
|
|
1366
|
+
This method should return an iterable, *not* an iterator.
|
|
1367
|
+
"""
|
|
1368
|
+
try:
|
|
1369
|
+
return [self.an_element()]
|
|
1370
|
+
except EmptySetError:
|
|
1371
|
+
return []
|
|
1372
|
+
|
|
1373
|
+
def _test_some_elements(self, **options):
|
|
1374
|
+
"""
|
|
1375
|
+
Run generic tests on the method :meth:`.some_elements`.
|
|
1376
|
+
|
|
1377
|
+
.. SEEALSO:: :class:`TestSuite`
|
|
1378
|
+
|
|
1379
|
+
EXAMPLES::
|
|
1380
|
+
|
|
1381
|
+
sage: C = Sets().example()
|
|
1382
|
+
sage: C._test_some_elements()
|
|
1383
|
+
|
|
1384
|
+
Let us now write a broken :meth:`.some_elements` method::
|
|
1385
|
+
|
|
1386
|
+
sage: from sage.categories.examples.sets_cat import *
|
|
1387
|
+
sage: class CCls(PrimeNumbers):
|
|
1388
|
+
....: def some_elements(self):
|
|
1389
|
+
....: return [self(17), 32]
|
|
1390
|
+
sage: CC = CCls()
|
|
1391
|
+
sage: CC._test_some_elements()
|
|
1392
|
+
Traceback (most recent call last):
|
|
1393
|
+
...
|
|
1394
|
+
AssertionError: the object 32 in self.some_elements() is not in self
|
|
1395
|
+
"""
|
|
1396
|
+
tester = self._tester(**options)
|
|
1397
|
+
elements = self.some_elements()
|
|
1398
|
+
# Todo: enable this once
|
|
1399
|
+
#tester.assertTrue(elements != iter(elements),
|
|
1400
|
+
# "self.some_elements() should return an iterable, not an iterator")
|
|
1401
|
+
for x in elements:
|
|
1402
|
+
tester.assertIn(x, self, LazyFormat(
|
|
1403
|
+
"the object %s in self.some_elements() is not in self") % (x,))
|
|
1404
|
+
|
|
1405
|
+
#Note: the four methods 'cardinality', 'is_finite_, 'is_empty' and
|
|
1406
|
+
# 'random_element' might or might not be implemented in the parent
|
|
1407
|
+
# objects. Most of the time a default implementation will be provided by
|
|
1408
|
+
# a subcategory of Sets. We do not declare them as optional abstract
|
|
1409
|
+
# methods to not pollute the namespace.
|
|
1410
|
+
|
|
1411
|
+
# def cardinality(self)
|
|
1412
|
+
# def is_finite(self)
|
|
1413
|
+
# def is_empty(self)
|
|
1414
|
+
# def random_element(self):
|
|
1415
|
+
|
|
1416
|
+
def _test_cardinality(self, **options):
|
|
1417
|
+
r"""
|
|
1418
|
+
Run generic test on the method :meth:`.cardinality`.
|
|
1419
|
+
|
|
1420
|
+
EXAMPLES::
|
|
1421
|
+
|
|
1422
|
+
sage: C = Sets().example()
|
|
1423
|
+
sage: C._test_cardinality()
|
|
1424
|
+
|
|
1425
|
+
Let us now write a broken :meth:`cardinality` method::
|
|
1426
|
+
|
|
1427
|
+
sage: from sage.categories.examples.sets_cat import *
|
|
1428
|
+
sage: class CCls(PrimeNumbers):
|
|
1429
|
+
....: def cardinality(self):
|
|
1430
|
+
....: return int(5)
|
|
1431
|
+
sage: CC = CCls()
|
|
1432
|
+
sage: CC._test_cardinality()
|
|
1433
|
+
Traceback (most recent call last):
|
|
1434
|
+
...
|
|
1435
|
+
AssertionError: the output of the method cardinality must either
|
|
1436
|
+
be a Sage integer or infinity. Not <... 'int'>.
|
|
1437
|
+
"""
|
|
1438
|
+
try:
|
|
1439
|
+
cardinality = self.cardinality()
|
|
1440
|
+
except (AttributeError,NotImplementedError):
|
|
1441
|
+
return
|
|
1442
|
+
from sage.structure.element import parent
|
|
1443
|
+
from sage.rings.infinity import Infinity
|
|
1444
|
+
from sage.rings.integer_ring import ZZ
|
|
1445
|
+
tester = self._tester(**options)
|
|
1446
|
+
tester.assertTrue(cardinality is Infinity or parent(cardinality) is ZZ,
|
|
1447
|
+
"the output of the method cardinality must either be a Sage integer or infinity. Not {}.".format(type(cardinality)))
|
|
1448
|
+
|
|
1449
|
+
# Functorial constructions
|
|
1450
|
+
|
|
1451
|
+
def construction(self):
|
|
1452
|
+
"""
|
|
1453
|
+
Return a pair ``(functor, parent)`` such that
|
|
1454
|
+
``functor(parent)`` returns ``self``. If ``self`` does
|
|
1455
|
+
not have a functorial construction, return ``None``.
|
|
1456
|
+
|
|
1457
|
+
EXAMPLES::
|
|
1458
|
+
|
|
1459
|
+
sage: QQ.construction()
|
|
1460
|
+
(FractionField, Integer Ring)
|
|
1461
|
+
sage: f, R = QQ['x'].construction()
|
|
1462
|
+
sage: f
|
|
1463
|
+
Poly[x]
|
|
1464
|
+
sage: R
|
|
1465
|
+
Rational Field
|
|
1466
|
+
sage: f(R)
|
|
1467
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
1468
|
+
"""
|
|
1469
|
+
return None
|
|
1470
|
+
|
|
1471
|
+
def _test_construction(self, **options):
|
|
1472
|
+
"""
|
|
1473
|
+
Test that the construction returned by ``self`` really yields ``self``.
|
|
1474
|
+
|
|
1475
|
+
:meth:`construction` either returns None or a pair ``(F, O)``,
|
|
1476
|
+
and if it returns the latter, then it is supposed that ``F(O) == self``.
|
|
1477
|
+
The test verifies this assumption.
|
|
1478
|
+
|
|
1479
|
+
EXAMPLES:
|
|
1480
|
+
|
|
1481
|
+
We create a parent that returns a wrong construction (its construction
|
|
1482
|
+
returns the rational field rather than the parent itself)::
|
|
1483
|
+
|
|
1484
|
+
sage: class P(Parent):
|
|
1485
|
+
....: Element = ElementWrapper
|
|
1486
|
+
....: def __init__(self):
|
|
1487
|
+
....: Parent.__init__(self, category=Sets())
|
|
1488
|
+
....: def __eq__(self, P):
|
|
1489
|
+
....: return type(self) == type(P)
|
|
1490
|
+
....: def __hash__(self):
|
|
1491
|
+
....: return hash(type(self))
|
|
1492
|
+
....: def construction(self):
|
|
1493
|
+
....: return sage.categories.pushout.FractionField(), ZZ
|
|
1494
|
+
....:
|
|
1495
|
+
sage: import __main__
|
|
1496
|
+
sage: __main__.P = P # this is to enable pickling in doctests
|
|
1497
|
+
sage: p = P()
|
|
1498
|
+
sage: F,R = p.construction()
|
|
1499
|
+
sage: F(R)
|
|
1500
|
+
Rational Field
|
|
1501
|
+
sage: TestSuite(p).run()
|
|
1502
|
+
Failure in _test_construction:
|
|
1503
|
+
Traceback (most recent call last):
|
|
1504
|
+
...
|
|
1505
|
+
AssertionError: the object's construction does not recreate this object
|
|
1506
|
+
...
|
|
1507
|
+
The following tests failed: _test_construction
|
|
1508
|
+
|
|
1509
|
+
If the parent returns the empty construction, the test will not complain::
|
|
1510
|
+
|
|
1511
|
+
sage: ZZ.construction() is None
|
|
1512
|
+
True
|
|
1513
|
+
sage: TestSuite(ZZ).run() # indirect doctest
|
|
1514
|
+
|
|
1515
|
+
If the construction works as expected, the test will not complain
|
|
1516
|
+
either::
|
|
1517
|
+
|
|
1518
|
+
sage: F,R = QQ.construction()
|
|
1519
|
+
sage: F(R) == QQ
|
|
1520
|
+
True
|
|
1521
|
+
sage: TestSuite(QQ).run() # indirect doctest
|
|
1522
|
+
"""
|
|
1523
|
+
tester = self._tester(**options)
|
|
1524
|
+
FO = self.construction()
|
|
1525
|
+
if FO is None:
|
|
1526
|
+
return
|
|
1527
|
+
tester.assertEqual(FO[0](FO[1]), self, "the object's construction does not recreate this object")
|
|
1528
|
+
|
|
1529
|
+
CartesianProduct = CartesianProduct
|
|
1530
|
+
|
|
1531
|
+
def cartesian_product(*parents, **kwargs):
|
|
1532
|
+
"""
|
|
1533
|
+
Return the Cartesian product of the parents.
|
|
1534
|
+
|
|
1535
|
+
INPUT:
|
|
1536
|
+
|
|
1537
|
+
- ``parents`` -- list (or other iterable) of parents
|
|
1538
|
+
|
|
1539
|
+
- ``category`` -- (default: ``None``) the category the
|
|
1540
|
+
Cartesian product belongs to. If ``None`` is passed,
|
|
1541
|
+
then
|
|
1542
|
+
:meth:`~sage.categories.covariant_functorial_construction.CovariantFactorialConstruction.category_from_parents`
|
|
1543
|
+
is used to determine the category.
|
|
1544
|
+
|
|
1545
|
+
- ``extra_category`` -- (default: ``None``) a category
|
|
1546
|
+
that is added to the Cartesian product in addition
|
|
1547
|
+
to the categories obtained from the parents.
|
|
1548
|
+
|
|
1549
|
+
- other keyword arguments will passed on to the class used
|
|
1550
|
+
for this Cartesian product (see also
|
|
1551
|
+
:class:`~sage.sets.cartesian_product.CartesianProduct`).
|
|
1552
|
+
|
|
1553
|
+
OUTPUT: the Cartesian product
|
|
1554
|
+
|
|
1555
|
+
EXAMPLES::
|
|
1556
|
+
|
|
1557
|
+
sage: C = AlgebrasWithBasis(QQ)
|
|
1558
|
+
sage: A = C.example(); A.rename('A') # needs sage.combinat sage.modules
|
|
1559
|
+
sage: A.cartesian_product(A, A) # needs sage.combinat sage.modules
|
|
1560
|
+
A (+) A (+) A
|
|
1561
|
+
sage: ZZ.cartesian_product(GF(2), FiniteEnumeratedSet([1,2,3]))
|
|
1562
|
+
The Cartesian product of (Integer Ring,
|
|
1563
|
+
Finite Field of size 2, {1, 2, 3})
|
|
1564
|
+
|
|
1565
|
+
sage: C = ZZ.cartesian_product(A); C # needs sage.combinat sage.modules
|
|
1566
|
+
The Cartesian product of (Integer Ring, A)
|
|
1567
|
+
|
|
1568
|
+
TESTS::
|
|
1569
|
+
|
|
1570
|
+
sage: type(C) # needs sage.combinat sage.modules
|
|
1571
|
+
<class 'sage.sets.cartesian_product.CartesianProduct_with_category'>
|
|
1572
|
+
sage: C.category() # needs sage.combinat sage.modules
|
|
1573
|
+
Join of Category of rings and ...
|
|
1574
|
+
and Category of Cartesian products of commutative additive groups
|
|
1575
|
+
|
|
1576
|
+
::
|
|
1577
|
+
|
|
1578
|
+
sage: cartesian_product([ZZ, ZZ], category=Sets()).category()
|
|
1579
|
+
Category of sets
|
|
1580
|
+
sage: cartesian_product([ZZ, ZZ]).category()
|
|
1581
|
+
Join of
|
|
1582
|
+
Category of Cartesian products of commutative rings and
|
|
1583
|
+
Category of Cartesian products of metric spaces and
|
|
1584
|
+
Category of Cartesian products of enumerated sets
|
|
1585
|
+
sage: cartesian_product([ZZ, ZZ], extra_category=Posets()).category()
|
|
1586
|
+
Join of
|
|
1587
|
+
Category of Cartesian products of commutative rings and
|
|
1588
|
+
Category of posets and
|
|
1589
|
+
Category of Cartesian products of metric spaces and
|
|
1590
|
+
Category of Cartesian products of enumerated sets
|
|
1591
|
+
"""
|
|
1592
|
+
category = kwargs.pop('category', None)
|
|
1593
|
+
extra_category = kwargs.pop('extra_category', None)
|
|
1594
|
+
|
|
1595
|
+
category = category or cartesian_product.category_from_parents(parents)
|
|
1596
|
+
if extra_category:
|
|
1597
|
+
if isinstance(category, (list, tuple)):
|
|
1598
|
+
category = tuple(category) + (extra_category,)
|
|
1599
|
+
else:
|
|
1600
|
+
category = category & extra_category
|
|
1601
|
+
return parents[0].CartesianProduct(parents, category=category, **kwargs)
|
|
1602
|
+
|
|
1603
|
+
def algebra(self, base_ring, category=None, **kwds):
|
|
1604
|
+
"""
|
|
1605
|
+
Return the algebra of ``self`` over ``base_ring``.
|
|
1606
|
+
|
|
1607
|
+
INPUT:
|
|
1608
|
+
|
|
1609
|
+
- ``self`` -- a parent `S`
|
|
1610
|
+
- ``base_ring`` -- a ring `K`
|
|
1611
|
+
- ``category`` -- a super category of the category
|
|
1612
|
+
of `S`, or ``None``
|
|
1613
|
+
|
|
1614
|
+
This returns the space of formal linear combinations of
|
|
1615
|
+
elements of `S` with coefficients in `K`, endowed with
|
|
1616
|
+
whatever structure can be induced from that of `S`.
|
|
1617
|
+
See the documentation of
|
|
1618
|
+
:mod:`sage.categories.algebra_functor` for details.
|
|
1619
|
+
|
|
1620
|
+
EXAMPLES:
|
|
1621
|
+
|
|
1622
|
+
If `S` is a :class:`group <Groups>`, the result is its
|
|
1623
|
+
group algebra `KS`::
|
|
1624
|
+
|
|
1625
|
+
sage: # needs sage.groups sage.modules
|
|
1626
|
+
sage: S = DihedralGroup(4); S
|
|
1627
|
+
Dihedral group of order 8 as a permutation group
|
|
1628
|
+
sage: A = S.algebra(QQ); A
|
|
1629
|
+
Algebra of Dihedral group of order 8 as a permutation group
|
|
1630
|
+
over Rational Field
|
|
1631
|
+
sage: A.category()
|
|
1632
|
+
Category of finite group algebras over Rational Field
|
|
1633
|
+
sage: a = A.an_element(); a
|
|
1634
|
+
() + (1,3) + 2*(1,3)(2,4) + 3*(1,4,3,2)
|
|
1635
|
+
|
|
1636
|
+
This space is endowed with an algebra structure, obtained
|
|
1637
|
+
by extending by bilinearity the multiplication of `G` to a
|
|
1638
|
+
multiplication on `RG`::
|
|
1639
|
+
|
|
1640
|
+
sage: a * a # needs sage.groups sage.modules
|
|
1641
|
+
6*() + 4*(2,4) + 3*(1,2)(3,4) + 12*(1,2,3,4) + 2*(1,3)
|
|
1642
|
+
+ 13*(1,3)(2,4) + 6*(1,4,3,2) + 3*(1,4)(2,3)
|
|
1643
|
+
|
|
1644
|
+
If `S` is a :class:`monoid <Monoids>`, the result is its
|
|
1645
|
+
monoid algebra `KS`::
|
|
1646
|
+
|
|
1647
|
+
sage: S = Monoids().example(); S
|
|
1648
|
+
An example of a monoid:
|
|
1649
|
+
the free monoid generated by ('a', 'b', 'c', 'd')
|
|
1650
|
+
sage: A = S.algebra(QQ); A # needs sage.modules
|
|
1651
|
+
Algebra of
|
|
1652
|
+
An example of a monoid: the free monoid generated by ('a', 'b', 'c', 'd')
|
|
1653
|
+
over Rational Field
|
|
1654
|
+
sage: A.category() # needs sage.modules
|
|
1655
|
+
Category of monoid algebras over Rational Field
|
|
1656
|
+
|
|
1657
|
+
Similarly, we can construct algebras for additive magmas,
|
|
1658
|
+
monoids, and groups.
|
|
1659
|
+
|
|
1660
|
+
One may specify for which category one takes the algebra;
|
|
1661
|
+
here we build the algebra of the additive group `GF_3`::
|
|
1662
|
+
|
|
1663
|
+
sage: # needs sage.modules
|
|
1664
|
+
sage: from sage.categories.additive_groups import AdditiveGroups
|
|
1665
|
+
sage: S = GF(7)
|
|
1666
|
+
sage: A = S.algebra(QQ, category=AdditiveGroups()); A
|
|
1667
|
+
Algebra of Finite Field of size 7 over Rational Field
|
|
1668
|
+
sage: A.category()
|
|
1669
|
+
Category of finite dimensional additive group algebras
|
|
1670
|
+
over Rational Field
|
|
1671
|
+
sage: a = A(S(1))
|
|
1672
|
+
sage: a
|
|
1673
|
+
1
|
|
1674
|
+
sage: 1 + a * a * a
|
|
1675
|
+
0 + 3
|
|
1676
|
+
|
|
1677
|
+
Note that the ``category`` keyword needs to be fed with
|
|
1678
|
+
the structure on `S` to be used, not the induced structure
|
|
1679
|
+
on the result.
|
|
1680
|
+
"""
|
|
1681
|
+
if category is None:
|
|
1682
|
+
category = self.category()
|
|
1683
|
+
from sage.categories.semigroups import Semigroups
|
|
1684
|
+
from sage.categories.commutative_additive_semigroups import CommutativeAdditiveSemigroups
|
|
1685
|
+
if category.is_subcategory(Semigroups()) and category.is_subcategory(CommutativeAdditiveSemigroups()):
|
|
1686
|
+
raise TypeError(
|
|
1687
|
+
""" `S = {}` is both an additive and a multiplicative semigroup.
|
|
1688
|
+
Constructing its algebra is ambiguous.
|
|
1689
|
+
Please use, e.g., S.algebra(QQ, category=Semigroups())""".format(self))
|
|
1690
|
+
from sage.categories.groups import Groups
|
|
1691
|
+
from sage.categories.additive_groups import AdditiveGroups
|
|
1692
|
+
from sage.algebras.group_algebra import GroupAlgebra_class
|
|
1693
|
+
algebra_category = category.Algebras(base_ring)
|
|
1694
|
+
if (category.is_subcategory(Groups())
|
|
1695
|
+
or category.is_subcategory(AdditiveGroups())):
|
|
1696
|
+
# Somewhat dirty hack to wrap non-atomic objects
|
|
1697
|
+
from sage.categories.modules_with_basis import ModulesWithBasis
|
|
1698
|
+
if self not in ModulesWithBasis:
|
|
1699
|
+
if 'prefix' not in kwds:
|
|
1700
|
+
kwds['prefix'] = ''
|
|
1701
|
+
if 'bracket' not in kwds:
|
|
1702
|
+
kwds['bracket'] = False
|
|
1703
|
+
result = GroupAlgebra_class(base_ring, self,
|
|
1704
|
+
category=algebra_category, **kwds)
|
|
1705
|
+
result.__doc__ = Sets.ParentMethods.algebra.__doc__
|
|
1706
|
+
return result
|
|
1707
|
+
|
|
1708
|
+
def _sympy_(self):
|
|
1709
|
+
"""
|
|
1710
|
+
Return an instance of a subclass of SymPy ``Set`` corresponding to ``self``.
|
|
1711
|
+
|
|
1712
|
+
The default implementation creates an instance of
|
|
1713
|
+
:class:`~sage.interfaces.sympy_wrapper`.
|
|
1714
|
+
|
|
1715
|
+
EXAMPLES::
|
|
1716
|
+
|
|
1717
|
+
sage: # needs sympy
|
|
1718
|
+
sage: F = FiniteEnumeratedSets().example(); F
|
|
1719
|
+
An example of a finite enumerated set: {1,2,3}
|
|
1720
|
+
sage: sF = F._sympy_(); sF
|
|
1721
|
+
SageSet(An example of a finite enumerated set: {1,2,3})
|
|
1722
|
+
sage: sF.is_finite_set
|
|
1723
|
+
True
|
|
1724
|
+
sage: bool(sF)
|
|
1725
|
+
True
|
|
1726
|
+
sage: len(sF)
|
|
1727
|
+
3
|
|
1728
|
+
sage: list(sF)
|
|
1729
|
+
[1, 2, 3]
|
|
1730
|
+
sage: from sympy import FiniteSet
|
|
1731
|
+
sage: FiniteSet.fromiter(sF) # random - this output is sympy >= 1.9
|
|
1732
|
+
FiniteSet(1, 2, 3)
|
|
1733
|
+
|
|
1734
|
+
sage: RR._sympy_().is_finite_set # needs sympy
|
|
1735
|
+
False
|
|
1736
|
+
|
|
1737
|
+
sage: F = Family([1, 2])
|
|
1738
|
+
sage: F is Family([1, 2])
|
|
1739
|
+
False
|
|
1740
|
+
sage: sF = F._sympy_(); sF # needs sympy
|
|
1741
|
+
SageSet(Family (1, 2))
|
|
1742
|
+
sage: sF._sage_() is F # needs sympy
|
|
1743
|
+
True
|
|
1744
|
+
"""
|
|
1745
|
+
from sage.interfaces.sympy_wrapper import SageSet
|
|
1746
|
+
from sage.interfaces.sympy import sympy_init
|
|
1747
|
+
sympy_init()
|
|
1748
|
+
return SageSet(self)
|
|
1749
|
+
|
|
1750
|
+
class ElementMethods:
|
|
1751
|
+
## Should eventually contain the basic operations which are no math
|
|
1752
|
+
## latex, hash, ...
|
|
1753
|
+
##def equal(x, y):
|
|
1754
|
+
##def =(x, y):
|
|
1755
|
+
|
|
1756
|
+
# Used by Element._test_category
|
|
1757
|
+
_dummy_attribute = None
|
|
1758
|
+
|
|
1759
|
+
def cartesian_product(*elements):
|
|
1760
|
+
"""
|
|
1761
|
+
Return the Cartesian product of its arguments, as an element of
|
|
1762
|
+
the Cartesian product of the parents of those elements.
|
|
1763
|
+
|
|
1764
|
+
EXAMPLES::
|
|
1765
|
+
|
|
1766
|
+
sage: C = AlgebrasWithBasis(QQ)
|
|
1767
|
+
sage: A = C.example() # needs sage.combinat sage.modules
|
|
1768
|
+
sage: a, b, c = A.algebra_generators() # needs sage.combinat sage.modules
|
|
1769
|
+
sage: a.cartesian_product(b, c) # needs sage.combinat sage.modules
|
|
1770
|
+
B[(0, word: a)] + B[(1, word: b)] + B[(2, word: c)]
|
|
1771
|
+
|
|
1772
|
+
FIXME: is this a policy that we want to enforce on all parents?
|
|
1773
|
+
"""
|
|
1774
|
+
from sage.structure.element import parent, Element
|
|
1775
|
+
assert all(isinstance(element, Element) for element in elements)
|
|
1776
|
+
parents = [parent(element) for element in elements]
|
|
1777
|
+
return cartesian_product(parents)._cartesian_product_of_elements(elements) # good name???
|
|
1778
|
+
|
|
1779
|
+
class MorphismMethods:
|
|
1780
|
+
@abstract_method(optional=True)
|
|
1781
|
+
def __invert__(self):
|
|
1782
|
+
r"""
|
|
1783
|
+
Return the inverse morphism, or raise an error.
|
|
1784
|
+
|
|
1785
|
+
The error may either state that the morphism is not
|
|
1786
|
+
invertible, or that Sage cannot invert it.
|
|
1787
|
+
|
|
1788
|
+
EXAMPLES::
|
|
1789
|
+
|
|
1790
|
+
sage: i = End(QQ).identity(); i
|
|
1791
|
+
Identity endomorphism of Rational Field
|
|
1792
|
+
sage: i.__invert__()
|
|
1793
|
+
Identity endomorphism of Rational Field
|
|
1794
|
+
|
|
1795
|
+
This method is meant to be used with the Python inversion
|
|
1796
|
+
operator `~`::
|
|
1797
|
+
|
|
1798
|
+
sage: ~i
|
|
1799
|
+
Identity endomorphism of Rational Field
|
|
1800
|
+
|
|
1801
|
+
We now try to inverse a couple of morphisms defined by a matrix::
|
|
1802
|
+
|
|
1803
|
+
sage: H = End(QQ^2) # needs sage.modules
|
|
1804
|
+
sage: phi = H(matrix([[1,1], [0,1]])); phi # needs sage.modules
|
|
1805
|
+
Vector space morphism represented by the matrix:
|
|
1806
|
+
[1 1]
|
|
1807
|
+
[0 1]
|
|
1808
|
+
Domain: Vector space of dimension 2 over Rational Field
|
|
1809
|
+
Codomain: Vector space of dimension 2 over Rational Field
|
|
1810
|
+
sage: ~phi # needs sage.modules
|
|
1811
|
+
Vector space morphism represented by the matrix:
|
|
1812
|
+
[ 1 -1]
|
|
1813
|
+
[ 0 1]
|
|
1814
|
+
Domain: Vector space of dimension 2 over Rational Field
|
|
1815
|
+
Codomain: Vector space of dimension 2 over Rational Field
|
|
1816
|
+
|
|
1817
|
+
sage: phi = H(matrix([[1,1], [1,1]])) # needs sage.modules
|
|
1818
|
+
sage: ~phi # needs sage.modules
|
|
1819
|
+
Traceback (most recent call last):
|
|
1820
|
+
...
|
|
1821
|
+
ZeroDivisionError: matrix morphism not invertible
|
|
1822
|
+
|
|
1823
|
+
.. NOTE::
|
|
1824
|
+
|
|
1825
|
+
This is an optional method. A default implementation
|
|
1826
|
+
raising :exc:`NotImplementedError` could be provided instead.
|
|
1827
|
+
"""
|
|
1828
|
+
|
|
1829
|
+
def is_bijective(self):
|
|
1830
|
+
r"""
|
|
1831
|
+
Return whether ``self`` is bijective.
|
|
1832
|
+
|
|
1833
|
+
EXAMPLES:
|
|
1834
|
+
|
|
1835
|
+
Two morphisms between vector spaces
|
|
1836
|
+
that are obviously not bijective, simply on
|
|
1837
|
+
considerations of the dimensions. However, each fulfills
|
|
1838
|
+
half of the requirements to be a bijection. ::
|
|
1839
|
+
|
|
1840
|
+
sage: # needs sage.modules
|
|
1841
|
+
sage: V1 = QQ^2
|
|
1842
|
+
sage: V2 = QQ^3
|
|
1843
|
+
sage: m = matrix(QQ, [[1, 2, 3], [4, 5, 6]])
|
|
1844
|
+
sage: phi = V1.hom(m, V2)
|
|
1845
|
+
sage: phi.is_injective()
|
|
1846
|
+
True
|
|
1847
|
+
sage: phi.is_bijective()
|
|
1848
|
+
False
|
|
1849
|
+
sage: rho = V2.hom(m.transpose(), V1)
|
|
1850
|
+
sage: rho.is_surjective()
|
|
1851
|
+
True
|
|
1852
|
+
sage: rho.is_bijective()
|
|
1853
|
+
False
|
|
1854
|
+
|
|
1855
|
+
We construct a simple bijection between two one-dimensional
|
|
1856
|
+
vector spaces. ::
|
|
1857
|
+
|
|
1858
|
+
sage: # needs sage.modules
|
|
1859
|
+
sage: V1 = QQ^3
|
|
1860
|
+
sage: V2 = QQ^2
|
|
1861
|
+
sage: phi = V1.hom(matrix(QQ, [[1, 2], [3, 4], [5, 6]]), V2)
|
|
1862
|
+
sage: x = vector(QQ, [1, -1, 4])
|
|
1863
|
+
sage: y = phi(x); y
|
|
1864
|
+
(18, 22)
|
|
1865
|
+
sage: rho = phi.restrict_domain(V1.span([x]))
|
|
1866
|
+
sage: zeta = rho.restrict_codomain(V2.span([y]))
|
|
1867
|
+
sage: zeta.is_bijective()
|
|
1868
|
+
True
|
|
1869
|
+
|
|
1870
|
+
AUTHOR:
|
|
1871
|
+
|
|
1872
|
+
- Rob Beezer (2011-06-28)
|
|
1873
|
+
"""
|
|
1874
|
+
return self.is_injective() and self.is_surjective()
|
|
1875
|
+
|
|
1876
|
+
def is_injective(self):
|
|
1877
|
+
r"""
|
|
1878
|
+
Return whether this map is injective.
|
|
1879
|
+
|
|
1880
|
+
EXAMPLES::
|
|
1881
|
+
|
|
1882
|
+
sage: f = ZZ.hom(GF(3)); f
|
|
1883
|
+
Natural morphism:
|
|
1884
|
+
From: Integer Ring
|
|
1885
|
+
To: Finite Field of size 3
|
|
1886
|
+
sage: f.is_injective()
|
|
1887
|
+
False
|
|
1888
|
+
"""
|
|
1889
|
+
if self.domain().cardinality() <= 1:
|
|
1890
|
+
return True
|
|
1891
|
+
if self.domain().cardinality() > self.codomain().cardinality():
|
|
1892
|
+
return False
|
|
1893
|
+
raise NotImplementedError
|
|
1894
|
+
|
|
1895
|
+
def is_surjective(self):
|
|
1896
|
+
"""
|
|
1897
|
+
Return whether the map is surjective.
|
|
1898
|
+
|
|
1899
|
+
TESTS::
|
|
1900
|
+
|
|
1901
|
+
sage: from sage.categories.map import Map
|
|
1902
|
+
sage: f = Map(Hom(QQ, ZZ, Rings()))
|
|
1903
|
+
sage: f.is_surjective()
|
|
1904
|
+
Traceback (most recent call last):
|
|
1905
|
+
...
|
|
1906
|
+
NotImplementedError
|
|
1907
|
+
"""
|
|
1908
|
+
raise NotImplementedError
|
|
1909
|
+
|
|
1910
|
+
def image(self, domain_subset=None):
|
|
1911
|
+
r"""
|
|
1912
|
+
Return the image of the domain or of ``domain_subset``.
|
|
1913
|
+
|
|
1914
|
+
EXAMPLES::
|
|
1915
|
+
|
|
1916
|
+
sage: # needs sage.combinat
|
|
1917
|
+
sage: P = Partitions(6)
|
|
1918
|
+
sage: H = Hom(P, ZZ)
|
|
1919
|
+
sage: f = H(ZZ.sum)
|
|
1920
|
+
sage: X = f.image() # needs sage.libs.flint
|
|
1921
|
+
sage: list(X) # needs sage.libs.flint
|
|
1922
|
+
[6]
|
|
1923
|
+
"""
|
|
1924
|
+
D = self.domain()
|
|
1925
|
+
if D is None:
|
|
1926
|
+
raise ValueError("this map became defunct by garbage collection")
|
|
1927
|
+
if domain_subset is None or domain_subset == D:
|
|
1928
|
+
try:
|
|
1929
|
+
if self.is_surjective():
|
|
1930
|
+
return D
|
|
1931
|
+
except NotImplementedError:
|
|
1932
|
+
pass
|
|
1933
|
+
domain_subset = D
|
|
1934
|
+
from sage.sets.set import Set_base
|
|
1935
|
+
from sage.sets.image_set import ImageSubobject, ImageSet
|
|
1936
|
+
if isinstance(domain_subset, Set_base):
|
|
1937
|
+
# Most of our parents are sets, but the mixin class Set_base
|
|
1938
|
+
# provides the full kit of operators. The image should get them too.
|
|
1939
|
+
cls = ImageSet
|
|
1940
|
+
else:
|
|
1941
|
+
cls = ImageSubobject
|
|
1942
|
+
return cls(self, domain_subset)
|
|
1943
|
+
|
|
1944
|
+
# Lazy imports to avoid circularity issues.
|
|
1945
|
+
Enumerated = LazyImport('sage.categories.enumerated_sets', 'EnumeratedSets', at_startup=True)
|
|
1946
|
+
Finite = LazyImport('sage.categories.finite_sets', 'FiniteSets', at_startup=True)
|
|
1947
|
+
Topological = LazyImport('sage.categories.topological_spaces',
|
|
1948
|
+
'TopologicalSpaces', 'Topological', at_startup=True)
|
|
1949
|
+
Metric = LazyImport('sage.categories.metric_spaces', 'MetricSpaces',
|
|
1950
|
+
'Metric', at_startup=True)
|
|
1951
|
+
from sage.categories.facade_sets import FacadeSets as Facade
|
|
1952
|
+
|
|
1953
|
+
class Infinite(CategoryWithAxiom):
|
|
1954
|
+
|
|
1955
|
+
class ParentMethods:
|
|
1956
|
+
|
|
1957
|
+
def is_finite(self):
|
|
1958
|
+
"""
|
|
1959
|
+
Return whether this set is finite.
|
|
1960
|
+
|
|
1961
|
+
Since this set is infinite this always returns ``False``.
|
|
1962
|
+
|
|
1963
|
+
EXAMPLES::
|
|
1964
|
+
|
|
1965
|
+
sage: C = InfiniteEnumeratedSets().example()
|
|
1966
|
+
sage: C.is_finite()
|
|
1967
|
+
False
|
|
1968
|
+
|
|
1969
|
+
TESTS::
|
|
1970
|
+
|
|
1971
|
+
sage: C.is_finite.__func__ is sage.categories.sets_cat.Sets.Infinite.ParentMethods.is_finite
|
|
1972
|
+
True
|
|
1973
|
+
"""
|
|
1974
|
+
return False
|
|
1975
|
+
|
|
1976
|
+
def is_empty(self):
|
|
1977
|
+
r"""
|
|
1978
|
+
Return whether this set is empty.
|
|
1979
|
+
|
|
1980
|
+
Since this set is infinite this always returns ``False``.
|
|
1981
|
+
|
|
1982
|
+
EXAMPLES::
|
|
1983
|
+
|
|
1984
|
+
sage: C = InfiniteEnumeratedSets().example()
|
|
1985
|
+
sage: C.is_empty()
|
|
1986
|
+
False
|
|
1987
|
+
"""
|
|
1988
|
+
return False
|
|
1989
|
+
|
|
1990
|
+
def cardinality(self):
|
|
1991
|
+
"""
|
|
1992
|
+
Count the elements of the enumerated set.
|
|
1993
|
+
|
|
1994
|
+
EXAMPLES::
|
|
1995
|
+
|
|
1996
|
+
sage: NN = InfiniteEnumeratedSets().example()
|
|
1997
|
+
sage: NN.cardinality()
|
|
1998
|
+
+Infinity
|
|
1999
|
+
"""
|
|
2000
|
+
from sage.rings.infinity import infinity
|
|
2001
|
+
return infinity
|
|
2002
|
+
|
|
2003
|
+
class Subquotients(SubquotientsCategory):
|
|
2004
|
+
"""
|
|
2005
|
+
A category for subquotients of sets.
|
|
2006
|
+
|
|
2007
|
+
.. SEEALSO:: :meth:`Sets().Subquotients`
|
|
2008
|
+
|
|
2009
|
+
EXAMPLES::
|
|
2010
|
+
|
|
2011
|
+
sage: Sets().Subquotients()
|
|
2012
|
+
Category of subquotients of sets
|
|
2013
|
+
sage: Sets().Subquotients().all_super_categories()
|
|
2014
|
+
[Category of subquotients of sets, Category of sets,
|
|
2015
|
+
Category of sets with partial maps,
|
|
2016
|
+
Category of objects]
|
|
2017
|
+
"""
|
|
2018
|
+
|
|
2019
|
+
class ParentMethods:
|
|
2020
|
+
|
|
2021
|
+
def _repr_(self):
|
|
2022
|
+
"""
|
|
2023
|
+
EXAMPLES::
|
|
2024
|
+
|
|
2025
|
+
sage: from sage.categories.examples.semigroups import IncompleteSubquotientSemigroup
|
|
2026
|
+
sage: S = IncompleteSubquotientSemigroup()
|
|
2027
|
+
sage: S._repr_()
|
|
2028
|
+
'A subquotient of An example of a semigroup: the left zero semigroup'
|
|
2029
|
+
"""
|
|
2030
|
+
return "A subquotient of %s" % (self.ambient())
|
|
2031
|
+
|
|
2032
|
+
@abstract_method
|
|
2033
|
+
def ambient(self):
|
|
2034
|
+
"""
|
|
2035
|
+
Return the ambient space for ``self``.
|
|
2036
|
+
|
|
2037
|
+
EXAMPLES::
|
|
2038
|
+
|
|
2039
|
+
sage: Semigroups().Subquotients().example().ambient()
|
|
2040
|
+
An example of a semigroup: the left zero semigroup
|
|
2041
|
+
|
|
2042
|
+
.. SEEALSO::
|
|
2043
|
+
|
|
2044
|
+
:meth:`Sets.SubcategoryMethods.Subquotients` for the
|
|
2045
|
+
specifications and :meth:`.lift` and :meth:`.retract`.
|
|
2046
|
+
"""
|
|
2047
|
+
|
|
2048
|
+
# Should lift and retract be declared as conversions to the coercion mechanism ?
|
|
2049
|
+
# Compatibility issue: in IntegerModRing, lift is a method returning the actual
|
|
2050
|
+
# lifting morphism::
|
|
2051
|
+
#
|
|
2052
|
+
# sage: F = IntegerModRing(3)
|
|
2053
|
+
# sage: F.lift()
|
|
2054
|
+
# Set-theoretic ring morphism:
|
|
2055
|
+
# From: Ring of integers modulo 3
|
|
2056
|
+
# To: Integer Ring
|
|
2057
|
+
# Defn: Choice of lifting map
|
|
2058
|
+
@abstract_method
|
|
2059
|
+
def lift(self, x):
|
|
2060
|
+
"""
|
|
2061
|
+
Lift `x` to the ambient space for ``self``.
|
|
2062
|
+
|
|
2063
|
+
INPUT:
|
|
2064
|
+
|
|
2065
|
+
- ``x`` -- an element of ``self``
|
|
2066
|
+
|
|
2067
|
+
EXAMPLES::
|
|
2068
|
+
|
|
2069
|
+
sage: S = Semigroups().Subquotients().example()
|
|
2070
|
+
sage: s = S.an_element()
|
|
2071
|
+
sage: s, s.parent()
|
|
2072
|
+
(42, An example of a (sub)quotient semigroup:
|
|
2073
|
+
a quotient of the left zero semigroup)
|
|
2074
|
+
sage: S.lift(s), S.lift(s).parent()
|
|
2075
|
+
(42, An example of a semigroup: the left zero semigroup)
|
|
2076
|
+
sage: s.lift(), s.lift().parent()
|
|
2077
|
+
(42, An example of a semigroup: the left zero semigroup)
|
|
2078
|
+
|
|
2079
|
+
.. SEEALSO::
|
|
2080
|
+
|
|
2081
|
+
:class:`Sets.SubcategoryMethods.Subquotients` for
|
|
2082
|
+
the specifications, :meth:`.ambient`, :meth:`.retract`,
|
|
2083
|
+
and also :meth:`Sets.Subquotients.ElementMethods.lift`.
|
|
2084
|
+
"""
|
|
2085
|
+
|
|
2086
|
+
@abstract_method
|
|
2087
|
+
def retract(self, x):
|
|
2088
|
+
"""
|
|
2089
|
+
Retract ``x`` to ``self``.
|
|
2090
|
+
|
|
2091
|
+
INPUT:
|
|
2092
|
+
|
|
2093
|
+
- ``x`` -- an element of the ambient space for ``self``
|
|
2094
|
+
|
|
2095
|
+
.. SEEALSO::
|
|
2096
|
+
|
|
2097
|
+
:class:`Sets.SubcategoryMethods.Subquotients` for
|
|
2098
|
+
the specifications, :meth:`.ambient`, :meth:`.retract`,
|
|
2099
|
+
and also :meth:`Sets.Subquotients.ElementMethods.retract`.
|
|
2100
|
+
|
|
2101
|
+
EXAMPLES::
|
|
2102
|
+
|
|
2103
|
+
sage: S = Semigroups().Subquotients().example()
|
|
2104
|
+
sage: s = S.ambient().an_element()
|
|
2105
|
+
sage: s, s.parent()
|
|
2106
|
+
(42, An example of a semigroup: the left zero semigroup)
|
|
2107
|
+
sage: S.retract(s), S.retract(s).parent()
|
|
2108
|
+
(42, An example of a (sub)quotient semigroup:
|
|
2109
|
+
a quotient of the left zero semigroup)
|
|
2110
|
+
"""
|
|
2111
|
+
|
|
2112
|
+
class ElementMethods:
|
|
2113
|
+
|
|
2114
|
+
def lift(self):
|
|
2115
|
+
"""
|
|
2116
|
+
Lift ``self`` to the ambient space for its parent.
|
|
2117
|
+
|
|
2118
|
+
EXAMPLES::
|
|
2119
|
+
|
|
2120
|
+
sage: S = Semigroups().Subquotients().example()
|
|
2121
|
+
sage: s = S.an_element()
|
|
2122
|
+
sage: s, s.parent()
|
|
2123
|
+
(42, An example of a (sub)quotient semigroup:
|
|
2124
|
+
a quotient of the left zero semigroup)
|
|
2125
|
+
sage: S.lift(s), S.lift(s).parent()
|
|
2126
|
+
(42, An example of a semigroup: the left zero semigroup)
|
|
2127
|
+
sage: s.lift(), s.lift().parent()
|
|
2128
|
+
(42, An example of a semigroup: the left zero semigroup)
|
|
2129
|
+
"""
|
|
2130
|
+
return self.parent().lift(self)
|
|
2131
|
+
|
|
2132
|
+
class Quotients(QuotientsCategory):
|
|
2133
|
+
"""
|
|
2134
|
+
A category for quotients of sets.
|
|
2135
|
+
|
|
2136
|
+
.. SEEALSO:: :meth:`Sets().Quotients`
|
|
2137
|
+
|
|
2138
|
+
EXAMPLES::
|
|
2139
|
+
|
|
2140
|
+
sage: Sets().Quotients()
|
|
2141
|
+
Category of quotients of sets
|
|
2142
|
+
sage: Sets().Quotients().all_super_categories()
|
|
2143
|
+
[Category of quotients of sets,
|
|
2144
|
+
Category of subquotients of sets,
|
|
2145
|
+
Category of sets,
|
|
2146
|
+
Category of sets with partial maps,
|
|
2147
|
+
Category of objects]
|
|
2148
|
+
"""
|
|
2149
|
+
|
|
2150
|
+
class ParentMethods:
|
|
2151
|
+
|
|
2152
|
+
def _repr_(self):
|
|
2153
|
+
"""
|
|
2154
|
+
EXAMPLES::
|
|
2155
|
+
|
|
2156
|
+
sage: from sage.categories.examples.semigroups import IncompleteSubquotientSemigroup
|
|
2157
|
+
sage: S = IncompleteSubquotientSemigroup(category=Semigroups().Quotients())
|
|
2158
|
+
sage: S._repr_()
|
|
2159
|
+
'A quotient of An example of a semigroup: the left zero semigroup'
|
|
2160
|
+
"""
|
|
2161
|
+
return "A quotient of {}".format(self.ambient())
|
|
2162
|
+
|
|
2163
|
+
def _an_element_(self):
|
|
2164
|
+
"""
|
|
2165
|
+
Return an element of ``self``, as per
|
|
2166
|
+
:meth:`Sets.ParentMethods.an_element`
|
|
2167
|
+
|
|
2168
|
+
EXAMPLES::
|
|
2169
|
+
|
|
2170
|
+
sage: S = FiniteEnumeratedSets().IsomorphicObjects().example()
|
|
2171
|
+
sage: S.an_element() # indirect doctest
|
|
2172
|
+
1
|
|
2173
|
+
"""
|
|
2174
|
+
return self.retract(self.ambient().an_element())
|
|
2175
|
+
|
|
2176
|
+
class Subobjects(SubobjectsCategory):
|
|
2177
|
+
"""
|
|
2178
|
+
A category for subobjects of sets.
|
|
2179
|
+
|
|
2180
|
+
.. SEEALSO:: :meth:`Sets().Subobjects`
|
|
2181
|
+
|
|
2182
|
+
EXAMPLES::
|
|
2183
|
+
|
|
2184
|
+
sage: Sets().Subobjects()
|
|
2185
|
+
Category of subobjects of sets
|
|
2186
|
+
sage: Sets().Subobjects().all_super_categories()
|
|
2187
|
+
[Category of subobjects of sets,
|
|
2188
|
+
Category of subquotients of sets,
|
|
2189
|
+
Category of sets,
|
|
2190
|
+
Category of sets with partial maps,
|
|
2191
|
+
Category of objects]
|
|
2192
|
+
"""
|
|
2193
|
+
|
|
2194
|
+
class ParentMethods:
|
|
2195
|
+
|
|
2196
|
+
def _repr_(self):
|
|
2197
|
+
"""
|
|
2198
|
+
EXAMPLES::
|
|
2199
|
+
|
|
2200
|
+
sage: from sage.categories.examples.semigroups import IncompleteSubquotientSemigroup
|
|
2201
|
+
sage: S = IncompleteSubquotientSemigroup(category=Semigroups().Subobjects())
|
|
2202
|
+
sage: S._repr_()
|
|
2203
|
+
'A subobject of An example of a semigroup: the left zero semigroup'
|
|
2204
|
+
"""
|
|
2205
|
+
return "A subobject of {}".format(self.ambient())
|
|
2206
|
+
|
|
2207
|
+
class IsomorphicObjects(IsomorphicObjectsCategory):
|
|
2208
|
+
"""
|
|
2209
|
+
A category for isomorphic objects of sets.
|
|
2210
|
+
|
|
2211
|
+
EXAMPLES::
|
|
2212
|
+
|
|
2213
|
+
sage: Sets().IsomorphicObjects()
|
|
2214
|
+
Category of isomorphic objects of sets
|
|
2215
|
+
sage: Sets().IsomorphicObjects().all_super_categories()
|
|
2216
|
+
[Category of isomorphic objects of sets,
|
|
2217
|
+
Category of subobjects of sets, Category of quotients of sets,
|
|
2218
|
+
Category of subquotients of sets,
|
|
2219
|
+
Category of sets,
|
|
2220
|
+
Category of sets with partial maps,
|
|
2221
|
+
Category of objects]
|
|
2222
|
+
"""
|
|
2223
|
+
|
|
2224
|
+
class ParentMethods:
|
|
2225
|
+
|
|
2226
|
+
def _repr_(self):
|
|
2227
|
+
"""
|
|
2228
|
+
EXAMPLES::
|
|
2229
|
+
|
|
2230
|
+
sage: S = FiniteEnumeratedSets().IsomorphicObjects().example()
|
|
2231
|
+
sage: S._repr_()
|
|
2232
|
+
'The image by some isomorphism of An example of a finite enumerated set: {1,2,3}'
|
|
2233
|
+
"""
|
|
2234
|
+
return "The image by some isomorphism of %s" % (self.ambient())
|
|
2235
|
+
|
|
2236
|
+
class CartesianProducts(CartesianProductsCategory):
|
|
2237
|
+
"""
|
|
2238
|
+
EXAMPLES::
|
|
2239
|
+
|
|
2240
|
+
sage: C = Sets().CartesianProducts().example()
|
|
2241
|
+
sage: C
|
|
2242
|
+
The Cartesian product of (Set of prime numbers (basic implementation),
|
|
2243
|
+
An example of an infinite enumerated set: the nonnegative integers,
|
|
2244
|
+
An example of a finite enumerated set: {1,2,3})
|
|
2245
|
+
sage: C.category()
|
|
2246
|
+
Category of Cartesian products of sets
|
|
2247
|
+
sage: C.categories()
|
|
2248
|
+
[Category of Cartesian products of sets, Category of sets,
|
|
2249
|
+
Category of sets with partial maps,
|
|
2250
|
+
Category of objects]
|
|
2251
|
+
sage: TestSuite(C).run()
|
|
2252
|
+
"""
|
|
2253
|
+
|
|
2254
|
+
def extra_super_categories(self):
|
|
2255
|
+
"""
|
|
2256
|
+
A Cartesian product of sets is a set.
|
|
2257
|
+
|
|
2258
|
+
EXAMPLES::
|
|
2259
|
+
|
|
2260
|
+
sage: Sets().CartesianProducts().extra_super_categories()
|
|
2261
|
+
[Category of sets]
|
|
2262
|
+
sage: Sets().CartesianProducts().super_categories()
|
|
2263
|
+
[Category of sets]
|
|
2264
|
+
"""
|
|
2265
|
+
return [Sets()]
|
|
2266
|
+
|
|
2267
|
+
def example(self):
|
|
2268
|
+
"""
|
|
2269
|
+
EXAMPLES::
|
|
2270
|
+
|
|
2271
|
+
sage: Sets().CartesianProducts().example()
|
|
2272
|
+
The Cartesian product of (Set of prime numbers (basic implementation),
|
|
2273
|
+
An example of an infinite enumerated set: the nonnegative integers,
|
|
2274
|
+
An example of a finite enumerated set: {1,2,3})
|
|
2275
|
+
"""
|
|
2276
|
+
from .finite_enumerated_sets import FiniteEnumeratedSets
|
|
2277
|
+
from .infinite_enumerated_sets import InfiniteEnumeratedSets
|
|
2278
|
+
from .cartesian_product import cartesian_product
|
|
2279
|
+
S1 = Sets().example()
|
|
2280
|
+
S2 = InfiniteEnumeratedSets().example()
|
|
2281
|
+
S3 = FiniteEnumeratedSets().example()
|
|
2282
|
+
return cartesian_product([S1, S2, S3])
|
|
2283
|
+
|
|
2284
|
+
class ParentMethods:
|
|
2285
|
+
def __iter__(self):
|
|
2286
|
+
r"""
|
|
2287
|
+
Return an iterator for the elements of this Cartesian product.
|
|
2288
|
+
|
|
2289
|
+
If all factors (except possibly the first factor) are known to be finite,
|
|
2290
|
+
it uses the lexicographic order.
|
|
2291
|
+
|
|
2292
|
+
Otherwise, the iterator enumerates the elements in increasing
|
|
2293
|
+
order of sum-of-ranks, refined by the reverse lexicographic order
|
|
2294
|
+
(see :func:`~sage.misc.mrange.cantor_product`).
|
|
2295
|
+
|
|
2296
|
+
EXAMPLES:
|
|
2297
|
+
|
|
2298
|
+
Sets are intrinsically unordered::
|
|
2299
|
+
|
|
2300
|
+
sage: for x,y in cartesian_product([Set([1,2]), Set(['a','b'])]): # random
|
|
2301
|
+
....: print((x, y))
|
|
2302
|
+
(1, 'b')
|
|
2303
|
+
(1, 'a')
|
|
2304
|
+
(2, 'b')
|
|
2305
|
+
(2, 'a')
|
|
2306
|
+
|
|
2307
|
+
sage: A = FiniteEnumeratedSets()(["a", "b"])
|
|
2308
|
+
sage: B = FiniteEnumeratedSets().example(); B
|
|
2309
|
+
An example of a finite enumerated set: {1,2,3}
|
|
2310
|
+
sage: C = cartesian_product([A, B, A]); C
|
|
2311
|
+
The Cartesian product of ({'a', 'b'}, An example of a finite enumerated set: {1,2,3}, {'a', 'b'})
|
|
2312
|
+
sage: C in FiniteEnumeratedSets()
|
|
2313
|
+
True
|
|
2314
|
+
sage: list(C)
|
|
2315
|
+
[('a', 1, 'a'), ('a', 1, 'b'), ('a', 2, 'a'), ('a', 2, 'b'), ('a', 3, 'a'), ('a', 3, 'b'),
|
|
2316
|
+
('b', 1, 'a'), ('b', 1, 'b'), ('b', 2, 'a'), ('b', 2, 'b'), ('b', 3, 'a'), ('b', 3, 'b')]
|
|
2317
|
+
sage: C.__iter__.__module__
|
|
2318
|
+
'sage.categories.sets_cat'
|
|
2319
|
+
|
|
2320
|
+
sage: F22 = GF(2).cartesian_product(GF(2))
|
|
2321
|
+
sage: list(F22)
|
|
2322
|
+
[(0, 0), (0, 1), (1, 0), (1, 1)]
|
|
2323
|
+
|
|
2324
|
+
sage: # needs sage.combinat
|
|
2325
|
+
sage: C = cartesian_product([Permutations(10)]*4)
|
|
2326
|
+
sage: it = iter(C)
|
|
2327
|
+
sage: next(it)
|
|
2328
|
+
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
2329
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
2330
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
2331
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
|
2332
|
+
sage: next(it)
|
|
2333
|
+
([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
2334
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
2335
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
2336
|
+
[1, 2, 3, 4, 5, 6, 7, 8, 10, 9])
|
|
2337
|
+
|
|
2338
|
+
When all factors (except possibly the first factor) are known to be finite, it
|
|
2339
|
+
uses the lexicographic order::
|
|
2340
|
+
|
|
2341
|
+
sage: it = iter(cartesian_product([ZZ, GF(2)]))
|
|
2342
|
+
sage: [next(it) for _ in range(10)]
|
|
2343
|
+
[(0, 0), (0, 1),
|
|
2344
|
+
(1, 0), (1, 1),
|
|
2345
|
+
(-1, 0), (-1, 1),
|
|
2346
|
+
(2, 0), (2, 1),
|
|
2347
|
+
(-2, 0), (-2, 1)]
|
|
2348
|
+
|
|
2349
|
+
When other factors are infinite (or not known to be finite), it enumerates
|
|
2350
|
+
the elements in increasing order of sum-of-ranks::
|
|
2351
|
+
|
|
2352
|
+
sage: NN = NonNegativeIntegers()
|
|
2353
|
+
sage: it = iter(cartesian_product([NN, NN]))
|
|
2354
|
+
sage: [next(it) for _ in range(10)]
|
|
2355
|
+
[(0, 0),
|
|
2356
|
+
(1, 0), (0, 1),
|
|
2357
|
+
(2, 0), (1, 1), (0, 2),
|
|
2358
|
+
(3, 0), (2, 1), (1, 2), (0, 3)]
|
|
2359
|
+
|
|
2360
|
+
An example with the first factor finite, the second infinite::
|
|
2361
|
+
|
|
2362
|
+
sage: it = iter(cartesian_product([GF(2), ZZ]))
|
|
2363
|
+
sage: [next(it) for _ in range(11)]
|
|
2364
|
+
[(0, 0),
|
|
2365
|
+
(1, 0), (0, 1),
|
|
2366
|
+
(1, 1), (0, -1),
|
|
2367
|
+
(1, -1), (0, 2),
|
|
2368
|
+
(1, 2), (0, -2),
|
|
2369
|
+
(1, -2), (0, 3)]
|
|
2370
|
+
|
|
2371
|
+
.. NOTE::
|
|
2372
|
+
|
|
2373
|
+
Here it would be faster to use :func:`itertools.product` for sets
|
|
2374
|
+
of small size. But the latter expands all factor in memory!
|
|
2375
|
+
So we can not reasonably use it in general.
|
|
2376
|
+
|
|
2377
|
+
ALGORITHM:
|
|
2378
|
+
|
|
2379
|
+
The lexicographic enumeration follows Recipe 19.9 in the Python Cookbook
|
|
2380
|
+
by Alex Martelli and David Ascher.
|
|
2381
|
+
"""
|
|
2382
|
+
factors = list(self.cartesian_factors())
|
|
2383
|
+
if any(f not in Sets().Finite() for f in factors[1:]):
|
|
2384
|
+
from sage.misc.mrange import cantor_product
|
|
2385
|
+
for t in cantor_product(*factors):
|
|
2386
|
+
yield self._cartesian_product_of_elements(t)
|
|
2387
|
+
return
|
|
2388
|
+
|
|
2389
|
+
# Lexicographic enumeration:
|
|
2390
|
+
# visualize an odometer, with "wheels" displaying "digits"...:
|
|
2391
|
+
wheels = [iter(f) for f in factors]
|
|
2392
|
+
try:
|
|
2393
|
+
digits = [next(it) for it in wheels]
|
|
2394
|
+
except StopIteration:
|
|
2395
|
+
return
|
|
2396
|
+
while True:
|
|
2397
|
+
yield self._cartesian_product_of_elements(digits)
|
|
2398
|
+
for i in range(len(digits)-1, -1, -1):
|
|
2399
|
+
try:
|
|
2400
|
+
digits[i] = next(wheels[i])
|
|
2401
|
+
break
|
|
2402
|
+
except StopIteration:
|
|
2403
|
+
wheels[i] = iter(factors[i])
|
|
2404
|
+
try:
|
|
2405
|
+
digits[i] = next(wheels[i])
|
|
2406
|
+
except StopIteration:
|
|
2407
|
+
return
|
|
2408
|
+
else:
|
|
2409
|
+
break
|
|
2410
|
+
|
|
2411
|
+
@cached_method
|
|
2412
|
+
def an_element(self):
|
|
2413
|
+
"""
|
|
2414
|
+
EXAMPLES::
|
|
2415
|
+
|
|
2416
|
+
sage: C = Sets().CartesianProducts().example(); C
|
|
2417
|
+
The Cartesian product of (Set of prime numbers (basic implementation),
|
|
2418
|
+
An example of an infinite enumerated set: the nonnegative integers,
|
|
2419
|
+
An example of a finite enumerated set: {1,2,3})
|
|
2420
|
+
sage: C.an_element()
|
|
2421
|
+
(47, 42, 1)
|
|
2422
|
+
"""
|
|
2423
|
+
return self._cartesian_product_of_elements(s.an_element() for s in self._sets)
|
|
2424
|
+
|
|
2425
|
+
def is_empty(self):
|
|
2426
|
+
r"""
|
|
2427
|
+
Return whether this set is empty.
|
|
2428
|
+
|
|
2429
|
+
EXAMPLES::
|
|
2430
|
+
|
|
2431
|
+
|
|
2432
|
+
sage: S1 = FiniteEnumeratedSet([1,2,3])
|
|
2433
|
+
sage: S2 = Set([])
|
|
2434
|
+
sage: cartesian_product([S1,ZZ]).is_empty()
|
|
2435
|
+
False
|
|
2436
|
+
sage: cartesian_product([S1,S2,S1]).is_empty()
|
|
2437
|
+
True
|
|
2438
|
+
|
|
2439
|
+
Even when some parent did not implement ``is_empty``,
|
|
2440
|
+
as long as one element is nonempty, the result can be determined::
|
|
2441
|
+
|
|
2442
|
+
sage: C = ConditionSet(QQ, lambda x: x > 0)
|
|
2443
|
+
sage: C.is_empty()
|
|
2444
|
+
Traceback (most recent call last):
|
|
2445
|
+
...
|
|
2446
|
+
AttributeError...
|
|
2447
|
+
sage: cartesian_product([C,[]]).is_empty()
|
|
2448
|
+
True
|
|
2449
|
+
sage: cartesian_product([C,C]).is_empty()
|
|
2450
|
+
Traceback (most recent call last):
|
|
2451
|
+
...
|
|
2452
|
+
NotImplementedError...
|
|
2453
|
+
"""
|
|
2454
|
+
last_exception = None
|
|
2455
|
+
for c in self.cartesian_factors():
|
|
2456
|
+
try:
|
|
2457
|
+
if c.is_empty():
|
|
2458
|
+
return True
|
|
2459
|
+
except (AttributeError, NotImplementedError) as e:
|
|
2460
|
+
last_exception = e
|
|
2461
|
+
if last_exception is not None:
|
|
2462
|
+
raise NotImplementedError from last_exception
|
|
2463
|
+
return False
|
|
2464
|
+
|
|
2465
|
+
def is_finite(self):
|
|
2466
|
+
r"""
|
|
2467
|
+
Return whether this set is finite.
|
|
2468
|
+
|
|
2469
|
+
EXAMPLES::
|
|
2470
|
+
|
|
2471
|
+
sage: E = FiniteEnumeratedSet([1,2,3])
|
|
2472
|
+
sage: C = cartesian_product([E, SymmetricGroup(4)]) # needs sage.groups
|
|
2473
|
+
sage: C.is_finite() # needs sage.groups
|
|
2474
|
+
True
|
|
2475
|
+
|
|
2476
|
+
sage: cartesian_product([ZZ,ZZ]).is_finite()
|
|
2477
|
+
False
|
|
2478
|
+
sage: cartesian_product([ZZ, Set(), ZZ]).is_finite()
|
|
2479
|
+
True
|
|
2480
|
+
|
|
2481
|
+
TESTS:
|
|
2482
|
+
|
|
2483
|
+
This should still work even if some parent does not implement
|
|
2484
|
+
``is_finite``::
|
|
2485
|
+
|
|
2486
|
+
sage: known_infinite_set = ZZ
|
|
2487
|
+
sage: unknown_infinite_set = Set([1]) + ConditionSet(QQ, lambda x: x > 0)
|
|
2488
|
+
sage: unknown_infinite_set.is_empty()
|
|
2489
|
+
False
|
|
2490
|
+
sage: unknown_infinite_set.is_finite()
|
|
2491
|
+
Traceback (most recent call last):
|
|
2492
|
+
...
|
|
2493
|
+
AttributeError...
|
|
2494
|
+
sage: cartesian_product([unknown_infinite_set, known_infinite_set]).is_finite()
|
|
2495
|
+
False
|
|
2496
|
+
sage: unknown_empty_set = ConditionSet(QQ, lambda x: False)
|
|
2497
|
+
sage: cartesian_product([known_infinite_set, unknown_empty_set]).is_finite()
|
|
2498
|
+
Traceback (most recent call last):
|
|
2499
|
+
...
|
|
2500
|
+
NotImplementedError...
|
|
2501
|
+
sage: cartesian_product([unknown_infinite_set, Set([])]).is_finite()
|
|
2502
|
+
True
|
|
2503
|
+
sage: cartesian_product([Set([1, 2, 3]), Set([4, 5])]).is_finite()
|
|
2504
|
+
True
|
|
2505
|
+
sage: cartesian_product([unknown_infinite_set, unknown_infinite_set]).is_finite()
|
|
2506
|
+
Traceback (most recent call last):
|
|
2507
|
+
...
|
|
2508
|
+
NotImplementedError...
|
|
2509
|
+
|
|
2510
|
+
Coverage test when one factor has emptiness unknown but result is finite::
|
|
2511
|
+
|
|
2512
|
+
sage: s = ConditionSet(RR, lambda x: x^2 == 2, category=Sets().Finite())
|
|
2513
|
+
sage: s.is_finite()
|
|
2514
|
+
True
|
|
2515
|
+
sage: s.is_empty()
|
|
2516
|
+
Traceback (most recent call last):
|
|
2517
|
+
...
|
|
2518
|
+
AttributeError...
|
|
2519
|
+
sage: cartesian_product([s, Set([1, 2, 3])]).is_finite()
|
|
2520
|
+
True
|
|
2521
|
+
"""
|
|
2522
|
+
try:
|
|
2523
|
+
# Note: some parent might not implement "is_empty". So we
|
|
2524
|
+
# carefully isolate this test.
|
|
2525
|
+
if self.is_empty():
|
|
2526
|
+
return True
|
|
2527
|
+
except (AttributeError, NotImplementedError):
|
|
2528
|
+
# it is unknown whether some set may be empty
|
|
2529
|
+
if all(c.is_finite() for c in self.cartesian_factors()):
|
|
2530
|
+
return True
|
|
2531
|
+
raise NotImplementedError
|
|
2532
|
+
|
|
2533
|
+
# in this case, all sets are definitely nonempty
|
|
2534
|
+
last_exception = None
|
|
2535
|
+
for c in self.cartesian_factors():
|
|
2536
|
+
try:
|
|
2537
|
+
if not c.is_finite():
|
|
2538
|
+
return False
|
|
2539
|
+
except (AttributeError, NotImplementedError) as e:
|
|
2540
|
+
last_exception = e
|
|
2541
|
+
if last_exception is not None:
|
|
2542
|
+
raise NotImplementedError from last_exception
|
|
2543
|
+
return True
|
|
2544
|
+
|
|
2545
|
+
def cardinality(self):
|
|
2546
|
+
r"""
|
|
2547
|
+
Return the cardinality of ``self``.
|
|
2548
|
+
|
|
2549
|
+
EXAMPLES::
|
|
2550
|
+
|
|
2551
|
+
sage: E = FiniteEnumeratedSet([1,2,3])
|
|
2552
|
+
sage: C = cartesian_product([E, SymmetricGroup(4)]) # needs sage.groups
|
|
2553
|
+
sage: C.cardinality() # needs sage.groups
|
|
2554
|
+
72
|
|
2555
|
+
|
|
2556
|
+
sage: E = FiniteEnumeratedSet([])
|
|
2557
|
+
sage: C = cartesian_product([E, ZZ, QQ])
|
|
2558
|
+
sage: C.cardinality()
|
|
2559
|
+
0
|
|
2560
|
+
|
|
2561
|
+
sage: C = cartesian_product([ZZ, QQ])
|
|
2562
|
+
sage: C.cardinality()
|
|
2563
|
+
+Infinity
|
|
2564
|
+
|
|
2565
|
+
sage: cartesian_product([GF(5), Permutations(10)]).cardinality()
|
|
2566
|
+
18144000
|
|
2567
|
+
sage: cartesian_product([GF(71)]*20).cardinality() == 71**20
|
|
2568
|
+
True
|
|
2569
|
+
"""
|
|
2570
|
+
f = self.cartesian_factors()
|
|
2571
|
+
|
|
2572
|
+
try:
|
|
2573
|
+
# Note: some parent might not implement "is_empty". So we
|
|
2574
|
+
# carefully isolate this test.
|
|
2575
|
+
is_empty = any(c.is_empty() for c in f)
|
|
2576
|
+
except (AttributeError,NotImplementedError):
|
|
2577
|
+
pass
|
|
2578
|
+
else:
|
|
2579
|
+
if is_empty:
|
|
2580
|
+
from sage.rings.integer_ring import ZZ
|
|
2581
|
+
return ZZ.zero()
|
|
2582
|
+
elif any(c in Sets().Infinite() for c in f):
|
|
2583
|
+
from sage.rings.infinity import Infinity
|
|
2584
|
+
return Infinity
|
|
2585
|
+
|
|
2586
|
+
from sage.misc.misc_c import prod
|
|
2587
|
+
return prod(c.cardinality() for c in f)
|
|
2588
|
+
|
|
2589
|
+
def random_element(self, *args):
|
|
2590
|
+
r"""
|
|
2591
|
+
Return a random element of this Cartesian product.
|
|
2592
|
+
|
|
2593
|
+
The extra arguments are passed down to each of the
|
|
2594
|
+
factors of the Cartesian product.
|
|
2595
|
+
|
|
2596
|
+
EXAMPLES::
|
|
2597
|
+
|
|
2598
|
+
sage: C = cartesian_product([Permutations(10)]*5)
|
|
2599
|
+
sage: C.random_element() # random
|
|
2600
|
+
([2, 9, 4, 7, 1, 8, 6, 10, 5, 3],
|
|
2601
|
+
[8, 6, 5, 7, 1, 4, 9, 3, 10, 2],
|
|
2602
|
+
[5, 10, 3, 8, 2, 9, 1, 4, 7, 6],
|
|
2603
|
+
[9, 6, 10, 3, 2, 1, 5, 8, 7, 4],
|
|
2604
|
+
[8, 5, 2, 9, 10, 3, 7, 1, 4, 6])
|
|
2605
|
+
|
|
2606
|
+
sage: C = cartesian_product([ZZ]*10)
|
|
2607
|
+
sage: c1 = C.random_element()
|
|
2608
|
+
sage: c1 # random
|
|
2609
|
+
(3, 1, 4, 1, 1, -3, 0, -4, -17, 2)
|
|
2610
|
+
sage: c2 = C.random_element(4,7)
|
|
2611
|
+
sage: c2 # random
|
|
2612
|
+
(6, 5, 6, 4, 5, 6, 6, 4, 5, 5)
|
|
2613
|
+
sage: all(4 <= i <= 7 for i in c2)
|
|
2614
|
+
True
|
|
2615
|
+
"""
|
|
2616
|
+
return self._cartesian_product_of_elements(
|
|
2617
|
+
c.random_element(*args) for c in self.cartesian_factors())
|
|
2618
|
+
|
|
2619
|
+
@abstract_method
|
|
2620
|
+
def _sets_keys(self):
|
|
2621
|
+
"""
|
|
2622
|
+
Return the indices of the Cartesian factors of ``self``.
|
|
2623
|
+
|
|
2624
|
+
EXAMPLES::
|
|
2625
|
+
|
|
2626
|
+
sage: cartesian_product([QQ, ZZ, ZZ])._sets_keys()
|
|
2627
|
+
{0, 1, 2}
|
|
2628
|
+
"""
|
|
2629
|
+
|
|
2630
|
+
@abstract_method
|
|
2631
|
+
def cartesian_factors(self):
|
|
2632
|
+
"""
|
|
2633
|
+
Return the Cartesian factors of ``self``.
|
|
2634
|
+
|
|
2635
|
+
EXAMPLES::
|
|
2636
|
+
|
|
2637
|
+
sage: cartesian_product([QQ, ZZ, ZZ]).cartesian_factors()
|
|
2638
|
+
(Rational Field, Integer Ring, Integer Ring)
|
|
2639
|
+
"""
|
|
2640
|
+
|
|
2641
|
+
@abstract_method
|
|
2642
|
+
def cartesian_projection(self, i):
|
|
2643
|
+
"""
|
|
2644
|
+
Return the natural projection onto the `i`-th
|
|
2645
|
+
Cartesian factor of ``self``.
|
|
2646
|
+
|
|
2647
|
+
INPUT:
|
|
2648
|
+
|
|
2649
|
+
- ``i`` -- the index of a Cartesian factor of ``self``
|
|
2650
|
+
|
|
2651
|
+
EXAMPLES::
|
|
2652
|
+
|
|
2653
|
+
sage: C = Sets().CartesianProducts().example(); C
|
|
2654
|
+
The Cartesian product of (Set of prime numbers (basic implementation),
|
|
2655
|
+
An example of an infinite enumerated set: the nonnegative integers,
|
|
2656
|
+
An example of a finite enumerated set: {1,2,3})
|
|
2657
|
+
sage: x = C.an_element(); x
|
|
2658
|
+
(47, 42, 1)
|
|
2659
|
+
sage: pi = C.cartesian_projection(1)
|
|
2660
|
+
sage: pi(x)
|
|
2661
|
+
42
|
|
2662
|
+
"""
|
|
2663
|
+
|
|
2664
|
+
def construction(self):
|
|
2665
|
+
"""
|
|
2666
|
+
The construction functor and the list of Cartesian factors.
|
|
2667
|
+
|
|
2668
|
+
EXAMPLES::
|
|
2669
|
+
|
|
2670
|
+
sage: C = cartesian_product([QQ, ZZ, ZZ])
|
|
2671
|
+
sage: C.construction()
|
|
2672
|
+
(The cartesian_product functorial construction,
|
|
2673
|
+
(Rational Field, Integer Ring, Integer Ring))
|
|
2674
|
+
"""
|
|
2675
|
+
return cartesian_product, self.cartesian_factors()
|
|
2676
|
+
|
|
2677
|
+
@abstract_method
|
|
2678
|
+
def _cartesian_product_of_elements(self, elements):
|
|
2679
|
+
"""
|
|
2680
|
+
Return the Cartesian product of the given ``elements``.
|
|
2681
|
+
|
|
2682
|
+
This method should accept any iterable.
|
|
2683
|
+
|
|
2684
|
+
INPUT:
|
|
2685
|
+
|
|
2686
|
+
- ``elements`` -- an iterable (e.g. a tuple or a list) of
|
|
2687
|
+
elements of each Cartesian factor of ``self``
|
|
2688
|
+
|
|
2689
|
+
EXAMPLES::
|
|
2690
|
+
|
|
2691
|
+
sage: S1 = Sets().example()
|
|
2692
|
+
sage: S2 = InfiniteEnumeratedSets().example()
|
|
2693
|
+
sage: X = [S2, S1, S2]
|
|
2694
|
+
sage: C = cartesian_product(X)
|
|
2695
|
+
sage: C._cartesian_product_of_elements([S.an_element() for S in X])
|
|
2696
|
+
(42, 47, 42)
|
|
2697
|
+
sage: C._cartesian_product_of_elements(S.an_element() for S in X)
|
|
2698
|
+
(42, 47, 42)
|
|
2699
|
+
"""
|
|
2700
|
+
|
|
2701
|
+
def _sympy_(self):
|
|
2702
|
+
"""
|
|
2703
|
+
Return a SymPy ``ProductSet`` corresponding to ``self``.
|
|
2704
|
+
|
|
2705
|
+
EXAMPLES::
|
|
2706
|
+
|
|
2707
|
+
sage: ZZ3 = cartesian_product([ZZ, ZZ, ZZ])
|
|
2708
|
+
sage: sZZ3 = ZZ3._sympy_(); sZZ3 # needs sympy
|
|
2709
|
+
ProductSet(Integers, Integers, Integers)
|
|
2710
|
+
sage: (1, 2, 3) in sZZ3 # needs sympy
|
|
2711
|
+
True
|
|
2712
|
+
"""
|
|
2713
|
+
from sympy import ProductSet
|
|
2714
|
+
from sage.interfaces.sympy import sympy_init
|
|
2715
|
+
sympy_init()
|
|
2716
|
+
return ProductSet(*self.cartesian_factors())
|
|
2717
|
+
|
|
2718
|
+
class ElementMethods:
|
|
2719
|
+
|
|
2720
|
+
def cartesian_projection(self, i):
|
|
2721
|
+
"""
|
|
2722
|
+
Return the projection of ``self`` onto the `i`-th
|
|
2723
|
+
factor of the Cartesian product.
|
|
2724
|
+
|
|
2725
|
+
INPUT:
|
|
2726
|
+
|
|
2727
|
+
- ``i`` -- the index of a factor of the Cartesian product
|
|
2728
|
+
|
|
2729
|
+
EXAMPLES::
|
|
2730
|
+
|
|
2731
|
+
sage: # needs sage.modules
|
|
2732
|
+
sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename('F')
|
|
2733
|
+
sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename('G')
|
|
2734
|
+
sage: S = cartesian_product([F, G])
|
|
2735
|
+
sage: x = (S.monomial((0,4)) + 2 * S.monomial((0,5))
|
|
2736
|
+
....: + 3 * S.monomial((1,6)))
|
|
2737
|
+
sage: x.cartesian_projection(0)
|
|
2738
|
+
B[4] + 2*B[5]
|
|
2739
|
+
sage: x.cartesian_projection(1)
|
|
2740
|
+
3*B[6]
|
|
2741
|
+
"""
|
|
2742
|
+
return self.parent().cartesian_projection(i)(self)
|
|
2743
|
+
|
|
2744
|
+
def cartesian_factors(self):
|
|
2745
|
+
"""
|
|
2746
|
+
Return the Cartesian factors of ``self``.
|
|
2747
|
+
|
|
2748
|
+
EXAMPLES::
|
|
2749
|
+
|
|
2750
|
+
sage: # needs sage.modules
|
|
2751
|
+
sage: F = CombinatorialFreeModule(ZZ, [4,5]); F.rename('F')
|
|
2752
|
+
sage: G = CombinatorialFreeModule(ZZ, [4,6]); G.rename('G')
|
|
2753
|
+
sage: H = CombinatorialFreeModule(ZZ, [4,7]); H.rename('H')
|
|
2754
|
+
sage: S = cartesian_product([F, G, H])
|
|
2755
|
+
sage: x = (S.monomial((0,4)) + 2 * S.monomial((0,5))
|
|
2756
|
+
....: + 3 * S.monomial((1,6)) + 4 * S.monomial((2,4))
|
|
2757
|
+
....: + 5 * S.monomial((2,7)))
|
|
2758
|
+
sage: x.cartesian_factors()
|
|
2759
|
+
(B[4] + 2*B[5], 3*B[6], 4*B[4] + 5*B[7])
|
|
2760
|
+
sage: [s.parent() for s in x.cartesian_factors()]
|
|
2761
|
+
[F, G, H]
|
|
2762
|
+
sage: S.zero().cartesian_factors()
|
|
2763
|
+
(0, 0, 0)
|
|
2764
|
+
sage: [s.parent() for s in S.zero().cartesian_factors()]
|
|
2765
|
+
[F, G, H]
|
|
2766
|
+
"""
|
|
2767
|
+
# TODO: optimize
|
|
2768
|
+
return tuple(self.cartesian_projection(i)
|
|
2769
|
+
for i in self.parent()._sets_keys())
|
|
2770
|
+
#return Family(self._sets.keys(), self.projection)
|
|
2771
|
+
|
|
2772
|
+
class Algebras(AlgebrasCategory):
|
|
2773
|
+
|
|
2774
|
+
def extra_super_categories(self):
|
|
2775
|
+
"""
|
|
2776
|
+
EXAMPLES::
|
|
2777
|
+
|
|
2778
|
+
sage: Sets().Algebras(ZZ).super_categories()
|
|
2779
|
+
[Category of modules with basis over Integer Ring]
|
|
2780
|
+
|
|
2781
|
+
sage: Sets().Algebras(QQ).extra_super_categories()
|
|
2782
|
+
[Category of vector spaces with basis over Rational Field]
|
|
2783
|
+
|
|
2784
|
+
sage: Sets().example().algebra(ZZ).categories() # needs sage.modules
|
|
2785
|
+
[Category of set algebras over Integer Ring,
|
|
2786
|
+
Category of modules with basis over Integer Ring,
|
|
2787
|
+
...
|
|
2788
|
+
Category of objects]
|
|
2789
|
+
"""
|
|
2790
|
+
from sage.categories.modules_with_basis import ModulesWithBasis
|
|
2791
|
+
return [ModulesWithBasis(self.base_ring())]
|
|
2792
|
+
|
|
2793
|
+
class ParentMethods:
|
|
2794
|
+
def construction(self):
|
|
2795
|
+
r"""
|
|
2796
|
+
Return the functorial construction of ``self``.
|
|
2797
|
+
|
|
2798
|
+
EXAMPLES::
|
|
2799
|
+
|
|
2800
|
+
sage: A = GroupAlgebra(KleinFourGroup(), QQ) # needs sage.groups sage.modules
|
|
2801
|
+
sage: F, arg = A.construction(); F, arg # needs sage.groups sage.modules
|
|
2802
|
+
(GroupAlgebraFunctor, Rational Field)
|
|
2803
|
+
sage: F(arg) is A # needs sage.groups sage.modules
|
|
2804
|
+
True
|
|
2805
|
+
|
|
2806
|
+
This also works for structures such as monoid algebras (see
|
|
2807
|
+
:issue:`27937`)::
|
|
2808
|
+
|
|
2809
|
+
sage: A = FreeAbelianMonoid('x,y').algebra(QQ) # needs sage.combinat sage.modules
|
|
2810
|
+
sage: F, arg = A.construction(); F, arg # needs sage.combinat sage.modules
|
|
2811
|
+
(The algebra functorial construction,
|
|
2812
|
+
Free abelian monoid on 2 generators (x, y))
|
|
2813
|
+
sage: F(arg) is A # needs sage.combinat sage.modules
|
|
2814
|
+
True
|
|
2815
|
+
"""
|
|
2816
|
+
from sage.categories.algebra_functor import (
|
|
2817
|
+
GroupAlgebraFunctor, AlgebraFunctor)
|
|
2818
|
+
try:
|
|
2819
|
+
group = self.group()
|
|
2820
|
+
except AttributeError:
|
|
2821
|
+
return (AlgebraFunctor(self.base_ring()),
|
|
2822
|
+
self.basis().keys())
|
|
2823
|
+
return GroupAlgebraFunctor(group), self.base_ring()
|
|
2824
|
+
|
|
2825
|
+
def _repr_(self):
|
|
2826
|
+
r"""
|
|
2827
|
+
Return the string representation of ``self``.
|
|
2828
|
+
|
|
2829
|
+
EXAMPLES::
|
|
2830
|
+
|
|
2831
|
+
sage: # needs sage.groups sage.modules
|
|
2832
|
+
sage: A = Groups().example().algebra(QQ); A
|
|
2833
|
+
Algebra of General Linear Group of degree 4 over Rational Field
|
|
2834
|
+
over Rational Field
|
|
2835
|
+
sage: A._name = "foo"
|
|
2836
|
+
sage: A
|
|
2837
|
+
foo over Rational Field
|
|
2838
|
+
sage: A = KleinFourGroup().algebra(ZZ)
|
|
2839
|
+
sage: A
|
|
2840
|
+
Algebra of The Klein 4 group of order 4, as a permutation group
|
|
2841
|
+
over Integer Ring
|
|
2842
|
+
"""
|
|
2843
|
+
if hasattr(self, "_name"):
|
|
2844
|
+
return self._name + " over {}".format(self.base_ring())
|
|
2845
|
+
else:
|
|
2846
|
+
return 'Algebra of {} over {}'.format(self.basis().keys(),
|
|
2847
|
+
self.base_ring())
|
|
2848
|
+
|
|
2849
|
+
class WithRealizations(WithRealizationsCategory):
|
|
2850
|
+
|
|
2851
|
+
def extra_super_categories(self):
|
|
2852
|
+
"""
|
|
2853
|
+
A set with multiple realizations is a facade parent.
|
|
2854
|
+
|
|
2855
|
+
EXAMPLES::
|
|
2856
|
+
|
|
2857
|
+
sage: Sets().WithRealizations().extra_super_categories()
|
|
2858
|
+
[Category of facade sets]
|
|
2859
|
+
sage: Sets().WithRealizations().super_categories()
|
|
2860
|
+
[Category of facade sets]
|
|
2861
|
+
"""
|
|
2862
|
+
return [Sets().Facade()]
|
|
2863
|
+
|
|
2864
|
+
def example(self, base_ring=None, set=None):
|
|
2865
|
+
r"""
|
|
2866
|
+
Return an example of set with multiple realizations, as
|
|
2867
|
+
per :meth:`Category.example`.
|
|
2868
|
+
|
|
2869
|
+
EXAMPLES::
|
|
2870
|
+
|
|
2871
|
+
sage: Sets().WithRealizations().example() # needs sage.modules
|
|
2872
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
2873
|
+
|
|
2874
|
+
sage: Sets().WithRealizations().example(ZZ, Set([1,2])) # needs sage.modules
|
|
2875
|
+
The subset algebra of {1, 2} over Integer Ring
|
|
2876
|
+
"""
|
|
2877
|
+
from sage.rings.rational_field import QQ
|
|
2878
|
+
from sage.sets.set import Set
|
|
2879
|
+
if base_ring is None:
|
|
2880
|
+
base_ring = QQ
|
|
2881
|
+
if set is None:
|
|
2882
|
+
set = Set([1,2,3])
|
|
2883
|
+
from sage.categories.examples.with_realizations import SubsetAlgebra
|
|
2884
|
+
return SubsetAlgebra(base_ring, set)
|
|
2885
|
+
|
|
2886
|
+
class ParentMethods:
|
|
2887
|
+
|
|
2888
|
+
def _test_with_realizations(self, **options):
|
|
2889
|
+
r"""
|
|
2890
|
+
Test that this parent with realizations is
|
|
2891
|
+
properly implemented.
|
|
2892
|
+
|
|
2893
|
+
INPUT:
|
|
2894
|
+
|
|
2895
|
+
- ``options`` -- any keyword arguments accepted
|
|
2896
|
+
by :meth:`_tester`
|
|
2897
|
+
|
|
2898
|
+
EXAMPLES::
|
|
2899
|
+
|
|
2900
|
+
sage: A = Sets().WithRealizations().example() # needs sage.modules
|
|
2901
|
+
sage: A._test_with_realizations() # needs sage.modules
|
|
2902
|
+
|
|
2903
|
+
See the documentation for :class:`TestSuite`
|
|
2904
|
+
for more information.
|
|
2905
|
+
"""
|
|
2906
|
+
tester = self._tester(**options)
|
|
2907
|
+
for R in self.realizations():
|
|
2908
|
+
tester.assertIn(R, self.Realizations())
|
|
2909
|
+
# Could check that there are coerce maps between any two realizations
|
|
2910
|
+
|
|
2911
|
+
@lazy_attribute
|
|
2912
|
+
def _realizations(self):
|
|
2913
|
+
"""
|
|
2914
|
+
This lazily initializes the attribute
|
|
2915
|
+
``_realizations`` the first time it is needed.
|
|
2916
|
+
|
|
2917
|
+
TESTS::
|
|
2918
|
+
|
|
2919
|
+
sage: class MyParent(Parent):
|
|
2920
|
+
....: pass
|
|
2921
|
+
sage: P = MyParent(category = Sets().WithRealizations())
|
|
2922
|
+
sage: P._realizations
|
|
2923
|
+
[]
|
|
2924
|
+
"""
|
|
2925
|
+
return []
|
|
2926
|
+
|
|
2927
|
+
def _register_realization(self, realization):
|
|
2928
|
+
"""
|
|
2929
|
+
EXAMPLES::
|
|
2930
|
+
|
|
2931
|
+
sage: # needs sage.combinat sage.modules
|
|
2932
|
+
sage: A = Sets().WithRealizations().example(QQ['x']); A
|
|
2933
|
+
The subset algebra of {1, 2, 3}
|
|
2934
|
+
over Univariate Polynomial Ring in x over Rational Field
|
|
2935
|
+
sage: class ANewRealizationOfA(CombinatorialFreeModule):
|
|
2936
|
+
....: pass
|
|
2937
|
+
sage: category = A.Realizations() & Algebras(QQ['x']).WithBasis()
|
|
2938
|
+
sage: R = ANewRealizationOfA(A.base_ring(), A.F().basis().keys(),
|
|
2939
|
+
....: category=category)
|
|
2940
|
+
sage: R in A.realizations() # indirect doctest
|
|
2941
|
+
True
|
|
2942
|
+
|
|
2943
|
+
Note: the test above uses ``QQ[x]`` to not interfere
|
|
2944
|
+
with other tests.
|
|
2945
|
+
"""
|
|
2946
|
+
assert realization.realization_of() is self
|
|
2947
|
+
self._realizations.append(realization)
|
|
2948
|
+
|
|
2949
|
+
def inject_shorthands(self, shorthands=None, verbose=True):
|
|
2950
|
+
"""
|
|
2951
|
+
Import standard shorthands into the global namespace.
|
|
2952
|
+
|
|
2953
|
+
INPUT:
|
|
2954
|
+
|
|
2955
|
+
- ``shorthands`` -- list (or iterable) of strings
|
|
2956
|
+
(default: ``self._shorthands``)
|
|
2957
|
+
or ``'all'`` (for ``self._shorthands_all``)
|
|
2958
|
+
- ``verbose`` -- boolean (default: ``True``);
|
|
2959
|
+
whether to print the defined shorthands
|
|
2960
|
+
|
|
2961
|
+
EXAMPLES:
|
|
2962
|
+
|
|
2963
|
+
When computing with a set with multiple realizations,
|
|
2964
|
+
like :class:`SymmetricFunctions` or
|
|
2965
|
+
:class:`~sage.categories.examples.with_realizations.SubsetAlgebra`,
|
|
2966
|
+
it is convenient to define shorthands for the various
|
|
2967
|
+
realizations, but cumbersome to do it by hand::
|
|
2968
|
+
|
|
2969
|
+
sage: S = SymmetricFunctions(ZZ); S # needs sage.combinat sage.modules
|
|
2970
|
+
Symmetric Functions over Integer Ring
|
|
2971
|
+
sage: s = S.s(); s # needs sage.combinat sage.modules
|
|
2972
|
+
Symmetric Functions over Integer Ring in the Schur basis
|
|
2973
|
+
sage: e = S.e(); e # needs sage.combinat sage.modules
|
|
2974
|
+
Symmetric Functions over Integer Ring in the elementary basis
|
|
2975
|
+
|
|
2976
|
+
This method automates the process::
|
|
2977
|
+
|
|
2978
|
+
sage: # needs sage.combinat sage.modules
|
|
2979
|
+
sage: S.inject_shorthands()
|
|
2980
|
+
Defining e as shorthand for
|
|
2981
|
+
Symmetric Functions over Integer Ring in the elementary basis
|
|
2982
|
+
Defining f as shorthand for
|
|
2983
|
+
Symmetric Functions over Integer Ring in the forgotten basis
|
|
2984
|
+
Defining h as shorthand for
|
|
2985
|
+
Symmetric Functions over Integer Ring in the homogeneous basis
|
|
2986
|
+
Defining m as shorthand for
|
|
2987
|
+
Symmetric Functions over Integer Ring in the monomial basis
|
|
2988
|
+
Defining p as shorthand for
|
|
2989
|
+
Symmetric Functions over Integer Ring in the powersum basis
|
|
2990
|
+
Defining s as shorthand for
|
|
2991
|
+
Symmetric Functions over Integer Ring in the Schur basis
|
|
2992
|
+
sage: s[1] + e[2] * p[1,1] + 2*h[3] + m[2,1]
|
|
2993
|
+
s[1] - 2*s[1, 1, 1] + s[1, 1, 1, 1] + s[2, 1]
|
|
2994
|
+
+ 2*s[2, 1, 1] + s[2, 2] + 2*s[3] + s[3, 1]
|
|
2995
|
+
sage: e
|
|
2996
|
+
Symmetric Functions over Integer Ring in the elementary basis
|
|
2997
|
+
sage: p
|
|
2998
|
+
Symmetric Functions over Integer Ring in the powersum basis
|
|
2999
|
+
sage: s
|
|
3000
|
+
Symmetric Functions over Integer Ring in the Schur basis
|
|
3001
|
+
|
|
3002
|
+
Sometimes, like for symmetric functions, one can
|
|
3003
|
+
request for all shorthands to be defined, including
|
|
3004
|
+
less common ones::
|
|
3005
|
+
|
|
3006
|
+
sage: S.inject_shorthands("all") # needs lrcalc_python sage.combinat sage.modules
|
|
3007
|
+
Defining e as shorthand for
|
|
3008
|
+
Symmetric Functions over Integer Ring in the elementary basis
|
|
3009
|
+
Defining f as shorthand for
|
|
3010
|
+
Symmetric Functions over Integer Ring in the forgotten basis
|
|
3011
|
+
Defining h as shorthand for
|
|
3012
|
+
Symmetric Functions over Integer Ring in the homogeneous basis
|
|
3013
|
+
Defining ht as shorthand for
|
|
3014
|
+
Symmetric Functions over Integer Ring in the
|
|
3015
|
+
induced trivial symmetric group character basis
|
|
3016
|
+
Defining m as shorthand for
|
|
3017
|
+
Symmetric Functions over Integer Ring in the monomial basis
|
|
3018
|
+
Defining o as shorthand for
|
|
3019
|
+
Symmetric Functions over Integer Ring in the orthogonal basis
|
|
3020
|
+
Defining p as shorthand for
|
|
3021
|
+
Symmetric Functions over Integer Ring in the powersum basis
|
|
3022
|
+
Defining s as shorthand for
|
|
3023
|
+
Symmetric Functions over Integer Ring in the Schur basis
|
|
3024
|
+
Defining sp as shorthand for
|
|
3025
|
+
Symmetric Functions over Integer Ring in the symplectic basis
|
|
3026
|
+
Defining st as shorthand for
|
|
3027
|
+
Symmetric Functions over Integer Ring in the
|
|
3028
|
+
irreducible symmetric group character basis
|
|
3029
|
+
Defining w as shorthand for
|
|
3030
|
+
Symmetric Functions over Integer Ring in the Witt basis
|
|
3031
|
+
|
|
3032
|
+
The messages can be silenced by setting ``verbose=False``::
|
|
3033
|
+
|
|
3034
|
+
sage: # needs sage.combinat sage.modules
|
|
3035
|
+
sage: Q = QuasiSymmetricFunctions(ZZ)
|
|
3036
|
+
sage: Q.inject_shorthands(verbose=False)
|
|
3037
|
+
sage: F[1,2,1] + 5*M[1,3] + F[2]^2
|
|
3038
|
+
5*F[1, 1, 1, 1] - 5*F[1, 1, 2] - 3*F[1, 2, 1] + 6*F[1, 3] +
|
|
3039
|
+
2*F[2, 2] + F[3, 1] + F[4]
|
|
3040
|
+
sage: F
|
|
3041
|
+
Quasisymmetric functions over the Integer Ring in the
|
|
3042
|
+
Fundamental basis
|
|
3043
|
+
sage: M
|
|
3044
|
+
Quasisymmetric functions over the Integer Ring in the
|
|
3045
|
+
Monomial basis
|
|
3046
|
+
|
|
3047
|
+
One can also just import a subset of the shorthands::
|
|
3048
|
+
|
|
3049
|
+
sage: # needs sage.combinat sage.modules
|
|
3050
|
+
sage: SQ = SymmetricFunctions(QQ)
|
|
3051
|
+
sage: SQ.inject_shorthands(['p', 's'], verbose=False)
|
|
3052
|
+
sage: p
|
|
3053
|
+
Symmetric Functions over Rational Field in the powersum basis
|
|
3054
|
+
sage: s
|
|
3055
|
+
Symmetric Functions over Rational Field in the Schur basis
|
|
3056
|
+
|
|
3057
|
+
Note that ``e`` is left unchanged::
|
|
3058
|
+
|
|
3059
|
+
sage: e # needs sage.combinat sage.modules
|
|
3060
|
+
Symmetric Functions over Integer Ring in the elementary basis
|
|
3061
|
+
|
|
3062
|
+
TESTS::
|
|
3063
|
+
|
|
3064
|
+
sage: e == S.e(), h == S.h(), m == S.m(), p == SQ.p(), s == SQ.s() # needs sage.combinat sage.modules
|
|
3065
|
+
(True, True, True, True, True)
|
|
3066
|
+
"""
|
|
3067
|
+
from sage.misc.misc import inject_variable
|
|
3068
|
+
if shorthands == 'all':
|
|
3069
|
+
shorthands = getattr(self, '_shorthands_all', None)
|
|
3070
|
+
if shorthands is None:
|
|
3071
|
+
shorthands = getattr(self, '_shorthands', None)
|
|
3072
|
+
if shorthands is None:
|
|
3073
|
+
raise NotImplementedError("no shorthands defined for {}".format(self))
|
|
3074
|
+
for shorthand in shorthands:
|
|
3075
|
+
realization = getattr(self, shorthand)()
|
|
3076
|
+
if verbose:
|
|
3077
|
+
print('Defining {} as shorthand for {}'.format(shorthand, realization))
|
|
3078
|
+
inject_variable(shorthand, realization, warn=False)
|
|
3079
|
+
|
|
3080
|
+
@abstract_method(optional=True)
|
|
3081
|
+
def a_realization(self):
|
|
3082
|
+
"""
|
|
3083
|
+
Return a realization of ``self``.
|
|
3084
|
+
|
|
3085
|
+
EXAMPLES::
|
|
3086
|
+
|
|
3087
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3088
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3089
|
+
sage: A.a_realization() # needs sage.modules
|
|
3090
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3091
|
+
in the Fundamental basis
|
|
3092
|
+
"""
|
|
3093
|
+
|
|
3094
|
+
def realizations(self):
|
|
3095
|
+
"""
|
|
3096
|
+
Return all the realizations of ``self`` that ``self``
|
|
3097
|
+
is aware of.
|
|
3098
|
+
|
|
3099
|
+
EXAMPLES::
|
|
3100
|
+
|
|
3101
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3102
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3103
|
+
sage: A.realizations() # needs sage.modules
|
|
3104
|
+
[The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis,
|
|
3105
|
+
The subset algebra of {1, 2, 3} over Rational Field in the In basis,
|
|
3106
|
+
The subset algebra of {1, 2, 3} over Rational Field in the Out basis]
|
|
3107
|
+
|
|
3108
|
+
.. NOTE::
|
|
3109
|
+
|
|
3110
|
+
Constructing a parent ``P`` in the category
|
|
3111
|
+
``A.Realizations()`` automatically adds ``P`` to
|
|
3112
|
+
this list by calling ``A._register_realization(A)``
|
|
3113
|
+
"""
|
|
3114
|
+
return self._realizations
|
|
3115
|
+
|
|
3116
|
+
def facade_for(self):
|
|
3117
|
+
"""
|
|
3118
|
+
Return the parents ``self`` is a facade for, that is
|
|
3119
|
+
the realizations of ``self``
|
|
3120
|
+
|
|
3121
|
+
EXAMPLES::
|
|
3122
|
+
|
|
3123
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3124
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3125
|
+
sage: A.facade_for() # needs sage.modules
|
|
3126
|
+
[The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis,
|
|
3127
|
+
The subset algebra of {1, 2, 3} over Rational Field in the In basis,
|
|
3128
|
+
The subset algebra of {1, 2, 3} over Rational Field in the Out basis]
|
|
3129
|
+
|
|
3130
|
+
sage: # needs sage.combinat sage.modules
|
|
3131
|
+
sage: A = Sets().WithRealizations().example(); A
|
|
3132
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3133
|
+
sage: f = A.F().an_element(); f
|
|
3134
|
+
F[{}] + 2*F[{1}] + 3*F[{2}] + F[{1, 2}]
|
|
3135
|
+
sage: i = A.In().an_element(); i
|
|
3136
|
+
In[{}] + 2*In[{1}] + 3*In[{2}] + In[{1, 2}]
|
|
3137
|
+
sage: o = A.Out().an_element(); o
|
|
3138
|
+
Out[{}] + 2*Out[{1}] + 3*Out[{2}] + Out[{1, 2}]
|
|
3139
|
+
sage: f in A, i in A, o in A
|
|
3140
|
+
(True, True, True)
|
|
3141
|
+
"""
|
|
3142
|
+
return self.realizations()
|
|
3143
|
+
|
|
3144
|
+
# Do we really want this feature?
|
|
3145
|
+
class Realizations(Category_realization_of_parent):
|
|
3146
|
+
|
|
3147
|
+
def super_categories(self):
|
|
3148
|
+
"""
|
|
3149
|
+
EXAMPLES::
|
|
3150
|
+
|
|
3151
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3152
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3153
|
+
sage: A.Realizations().super_categories() # needs sage.modules
|
|
3154
|
+
[Category of realizations of sets]
|
|
3155
|
+
"""
|
|
3156
|
+
return [Sets().Realizations()]
|
|
3157
|
+
|
|
3158
|
+
def _an_element_(self):
|
|
3159
|
+
"""
|
|
3160
|
+
Return an element of some realization of ``self``.
|
|
3161
|
+
|
|
3162
|
+
EXAMPLES::
|
|
3163
|
+
|
|
3164
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3165
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3166
|
+
sage: A.an_element() # indirect doctest # needs sage.modules
|
|
3167
|
+
F[{}] + 2*F[{1}] + 3*F[{2}] + F[{1, 2}]
|
|
3168
|
+
|
|
3169
|
+
TESTS:
|
|
3170
|
+
|
|
3171
|
+
Check that we are consistent no matter which basis is
|
|
3172
|
+
created first::
|
|
3173
|
+
|
|
3174
|
+
sage: M = posets.BooleanLattice(4).moebius_algebra(QQ) # needs sage.graphs sage.modules
|
|
3175
|
+
sage: I = M.I() # needs sage.graphs sage.modules
|
|
3176
|
+
sage: M._an_element_() # needs sage.graphs sage.modules
|
|
3177
|
+
2*E[0] + 2*E[1] + 3*E[2]
|
|
3178
|
+
"""
|
|
3179
|
+
return self.a_realization().an_element()
|
|
3180
|
+
|
|
3181
|
+
# TODO: maybe this could be taken care of by Sets.Facade()?
|
|
3182
|
+
def __contains__(self, x):
|
|
3183
|
+
r"""
|
|
3184
|
+
Test whether ``x`` is in ``self``, that is if it is an
|
|
3185
|
+
element of some realization of ``self``.
|
|
3186
|
+
|
|
3187
|
+
EXAMPLES::
|
|
3188
|
+
|
|
3189
|
+
sage: # needs sage.combinat sage.modules
|
|
3190
|
+
sage: A = Sets().WithRealizations().example(); A
|
|
3191
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3192
|
+
sage: A.an_element() in A
|
|
3193
|
+
True
|
|
3194
|
+
sage: A.In().an_element() in A
|
|
3195
|
+
True
|
|
3196
|
+
sage: A.F().an_element() in A
|
|
3197
|
+
True
|
|
3198
|
+
sage: A.Out().an_element() in A
|
|
3199
|
+
True
|
|
3200
|
+
sage: 1 in A
|
|
3201
|
+
True
|
|
3202
|
+
sage: QQ['x'].an_element() in A
|
|
3203
|
+
False
|
|
3204
|
+
"""
|
|
3205
|
+
return any(x in realization for realization in self.realizations())
|
|
3206
|
+
|
|
3207
|
+
class Realizations(RealizationsCategory):
|
|
3208
|
+
|
|
3209
|
+
class ParentMethods:
|
|
3210
|
+
|
|
3211
|
+
def __init_extra__(self):
|
|
3212
|
+
"""
|
|
3213
|
+
Register ``self`` as a realization of ``self.realization_of``.
|
|
3214
|
+
|
|
3215
|
+
TESTS::
|
|
3216
|
+
|
|
3217
|
+
sage: A = Sets().WithRealizations().example() # needs sage.modules
|
|
3218
|
+
sage: A.realizations() # indirect doctest # needs sage.modules
|
|
3219
|
+
[The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis,
|
|
3220
|
+
The subset algebra of {1, 2, 3} over Rational Field in the In basis,
|
|
3221
|
+
The subset algebra of {1, 2, 3} over Rational Field in the Out basis]
|
|
3222
|
+
"""
|
|
3223
|
+
self.realization_of()._register_realization(self)
|
|
3224
|
+
|
|
3225
|
+
@cached_method
|
|
3226
|
+
def realization_of(self):
|
|
3227
|
+
"""
|
|
3228
|
+
Return the parent this is a realization of.
|
|
3229
|
+
|
|
3230
|
+
EXAMPLES::
|
|
3231
|
+
|
|
3232
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3233
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3234
|
+
sage: In = A.In(); In # needs sage.modules
|
|
3235
|
+
The subset algebra of {1, 2, 3} over Rational Field in the In basis
|
|
3236
|
+
sage: In.realization_of() # needs sage.modules
|
|
3237
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3238
|
+
"""
|
|
3239
|
+
for category in self.categories():
|
|
3240
|
+
if isinstance(category, Category_realization_of_parent):
|
|
3241
|
+
return category.base()
|
|
3242
|
+
|
|
3243
|
+
def _realization_name(self):
|
|
3244
|
+
"""
|
|
3245
|
+
Return the name of this realization.
|
|
3246
|
+
|
|
3247
|
+
In this default implementation, this is guessed from
|
|
3248
|
+
the name of its class.
|
|
3249
|
+
|
|
3250
|
+
EXAMPLES::
|
|
3251
|
+
|
|
3252
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3253
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3254
|
+
sage: In = A.In(); In # needs sage.modules
|
|
3255
|
+
The subset algebra of {1, 2, 3} over Rational Field in the In basis
|
|
3256
|
+
sage: In._realization_name() # needs sage.modules
|
|
3257
|
+
'In'
|
|
3258
|
+
"""
|
|
3259
|
+
# The __base__ gets rid of the with_category
|
|
3260
|
+
# The split adds support for nested classes
|
|
3261
|
+
return self.__class__.__base__.__name__.split('.')[-1]
|
|
3262
|
+
|
|
3263
|
+
def _repr_(self):
|
|
3264
|
+
"""
|
|
3265
|
+
EXAMPLES::
|
|
3266
|
+
|
|
3267
|
+
sage: A = Sets().WithRealizations().example(); A # needs sage.modules
|
|
3268
|
+
The subset algebra of {1, 2, 3} over Rational Field
|
|
3269
|
+
sage: In = A.In(); In # needs sage.modules
|
|
3270
|
+
The subset algebra of {1, 2, 3} over Rational Field in the In basis
|
|
3271
|
+
|
|
3272
|
+
In the example above, :meth:`repr` was overridden by
|
|
3273
|
+
the category ``A.Realizations()``. We now add a new
|
|
3274
|
+
(fake) realization which is not in
|
|
3275
|
+
``A.Realizations()`` to actually exercise this
|
|
3276
|
+
method::
|
|
3277
|
+
|
|
3278
|
+
sage: from sage.categories.realizations import Realizations
|
|
3279
|
+
sage: class Blah(Parent):
|
|
3280
|
+
....: pass
|
|
3281
|
+
sage: C = Sets.WithRealizations.ParentMethods.Realizations(A) # needs sage.modules
|
|
3282
|
+
sage: P = Blah(category=C) # needs sage.modules
|
|
3283
|
+
sage: P # indirect doctest # needs sage.modules
|
|
3284
|
+
The subset algebra of {1, 2, 3} over Rational Field in the realization Blah
|
|
3285
|
+
"""
|
|
3286
|
+
return "{} in the realization {}".format(self.realization_of(), self._realization_name())
|
|
3287
|
+
|
|
3288
|
+
|
|
3289
|
+
# Moved from sage.categories.cartesian_product to avoid circular import errors
|
|
3290
|
+
cartesian_product = CartesianProductFunctor()
|