class Algebras(AlgebrasCategory): extra_super_categories = raw_getattr(Groups.Finite.Algebras, "extra_super_categories") class ParentMethods: __init_extra__ = raw_getattr( Groups.Finite.Algebras.ParentMethods, "__init_extra__")
def __init_extra__(self): """ sage: S = Semigroups().example("free") sage: S('a') * S('b') # indirect doctest 'ab' sage: S('a').__class__._mul_ == S('a').__class__._mul_parent True """ # This should instead register the multiplication to the coercion model # But this is not yet implemented in the coercion model # # Trac ticket #11900: The following used to test whether # self.product != self.product_from_element_class_mul. But # that is, of course, a bug. Namely otherwise, if the parent # has an optimized `product` then its elements will *always* use # a slow generic `_mul_`. # # So, in addition, it should be tested whether the element class exists # *and* has a custom _mul_, because in this case it must not be overridden. if (self.product.__func__ == self.product_from_element_class_mul.__func__): return if not (hasattr(self, "element_class") and hasattr(self.element_class, "_mul_parent")): return E = self.element_class E_mul_func = raw_getattr(E, '_mul_') if not isinstance(E_mul_func, AbstractMethod): C = self.category().element_class try: C_mul_func = raw_getattr(C, '_mul_') except AttributeError: # Doesn't have _mul_ return if isinstance(C_mul_func, AbstractMethod): return if E_mul_func is C_mul_func: # self.product is custom, thus, we rely on it E._mul_ = E._mul_parent else: # E._mul_ has so far been abstract E._mul_ = E._mul_parent
class AutomaticMonoid(AutomaticSemigroup): def one(self): """ Return the unit of ``self``. EXAMPLES:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup sage: R = IntegerModRing(21) sage: M = R.submonoid(()) sage: M.one() 1 sage: M.one().parent() is M True """ return self._one # This method takes the monoid generators and adds the unit semigroup_generators = raw_getattr(Monoids.ParentMethods, "semigroup_generators") def monoid_generators(self): """ Return the family of monoid generators of ``self``. EXAMPLES:: sage: from sage.monoids.automatic_semigroup import AutomaticSemigroup sage: R = IntegerModRing(28) sage: M = R.submonoid(Family({1: R(3), 2: R(5)})) sage: M.monoid_generators() Finite family {1: 3, 2: 5} Note that the monoid generators do not include the unit, unlike the semigroup generators:: sage: M.semigroup_generators() Family (1, 3, 5) """ return self._generators gens = monoid_generators
class Algebras(AlgebrasCategory): """ EXAMPLES:: Oops, the pretty printing is broken (the `s` is not removed properly) sage: Semigroups().SetsWithAction().Algebras(QQ) Category of sets endowed with an action of a semigrou algebras over Rational Field sage: Semigroups().SetsWithAction().Algebras(QQ) # todo: not implemented Category of sets endowed with an action of a semigrou algebras over Rational Field """ # see the warning in sage.categories.set_with_action_functor.SetsWithActionCategory._algebras_extra_super_categories extra_super_categories = raw_getattr(SetsWithActionCategory, "_algebras_extra_super_categories") class ParentMethods: def semigroup(self): """ EXAMPLES:: sage: M = Semigroups().SetsWithAction().example().algebra(QQ) sage: S = M.semigroup() """ return self.basis().keys().semigroup() def action(self, s, x): """ Return the action of ``s`` on ``x``. It is obtained by extending by linearity the action of ``s`` on the basis. INPUT: - ``x`` -- an element of ``self`` - ``s`` -- an element of the semigroup acting on ``self`` EXAMPLES:: sage: M = Semigroups().SetsWithAction().example().algebra(QQ); M Free module generated by Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication over Rational Field sage: S = M.semigroup() sage: f2, f3 = S.semigroup_generators() sage: x = M.an_element(); x 2*B[0] + 2*B[1] + 3*B[2] sage: M.action(f2, x) 2*B[0] + 2*B[2] + 3*B[4] """ action = self.basis().keys().action return x.map_support_skip_none(functools.partial(action, s)) @cached_method def side(self): """ Returns on which side the action occurs EXAMPLES:: sage: M = Semigroups().Finite().example() sage: M.regular_representation(side='left').side() 'left' sage: M.regular_representation(side='right').side() 'right' sage: M.regular_representation(side="left").side.__module__ 'sage.categories.sets_with_action' """ return self.basis().keys().side() def character_of(self, s): """ Return the trace of `s` as a linear morphism acting on ``self`` INPUT: - `s` -- an element of the semigroup acting on ``self`` EXAMPLES:: sage: S = AperiodicMonoids().Finite().example(3); S The finite H-trivial monoid of order preserving maps on {1, .., 3} sage: A = S.lr_regular_class_module(1, side="left") sage: pi = S.monoid_generators() sage: pi Finite family {1: 113, 2: 122, -2: 133, -1: 223} sage: A.character_of(S.one()) 3 sage: A.character_of(pi[1]) 1 .. seealso: :meth:`Semigroups.SetsWithAction.ParentMethods.nr_fixed_points` """ return self.basis().keys().nr_fixed_points(s) ######################################################################## # EXPERIMENTAL, MOSTLY FOR H-TRIVIAL AND PROBABLY NOW USELESS ######################################################################## def annihilator_with_apex(self, J): """ INPUT: - ``J`` -- the index of a regular J-class Let `A` be the set of all the elements of the semigroup which are not below `J` in `J`-order. This returns `Ann(self, A)`. """ S = self.semigroup() P = S.j_poset_on_regular_classes() A = set(P).difference(P.principal_order_filter(J)) # It is sufficient to take the generators of the highest J-classes in A A = P.order_ideal_generators(A) A = [x for I in A for x in S.regular_j_class_semigroup_generators(I)] return self.annihilator_of_subsemigroup(A) @cached_method def annihilator_module_with_apex(self, J): """ INPUT: - ``J`` -- the index of a regular J-class This attempts to construct a submodule of `self` with apex `J`. To this hand, this constructs the annihilator with apex `J` (see :meth:`annihilator_with_apex`), and checks whether it is indeed a submodule, and that its apex is `J`. If not, `None` is returned. EXAMPLES:: sage: M = Semigroups().SetsWithAction().example().algebra(QQ); M Free module generated by Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication over Rational Field sage: S = M.semigroup() This semigroup has two regular `J`-classes, with that indexed by `1` being smaller than that indexed by `0` (no luck in the random indexing chosen by Sage):: sage: S.j_poset_on_regular_classes().cover_relations() [[1, 0]] To those `J`-classes correspond two submodules of M:: sage: M.annihilator_module_with_apex(0) Vector space of degree 10 and dimension 5 over Rational Field Basis matrix: [ 1 0 0 0 0 -1 0 0 0 0] [ 0 1 0 0 0 0 -1 0 0 0] [ 0 0 1 0 0 0 0 -1 0 0] [ 0 0 0 1 0 0 0 0 -1 0] [ 0 0 0 0 1 0 0 0 0 -1] sage: M.annihilator_module_with_apex(1) Vector space of degree 10 and dimension 10 over Rational Field Basis matrix: [1 0 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0] [0 0 0 0 0 0 1 0 0 0] [0 0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 0 0 1] sage: M.annihilator_module_with_apex(0).apex() 0 sage: M.annihilator_module_with_apex(1).apex() 1 We conclude with a case where the construction fails. Consider the right class module of the BiHecke Monoid of type A_3, indexed by `2314 = s_2 s_1`: sage: W = SymmetricGroup(4) sage: S = BiHeckeMonoid(W); S bi-Hecke monoid of Symmetric group of order 4! as a permutation group sage: w = W([2,3,1,4]) sage: R = S.lr_regular_class_module(w, side='right') sage: list(f(W.one()) for f in R.basis().keys()) [(2,3), (1,2,3), ()] In this case, the construction fails:: sage: R.annihilator_module_with_apex(W([2,1,3,4])) # long time sage: R.annihilator_module_with_apex(W([1,3,2,4])) # long time Indeed, the annihilator subspaces (which are respectively the kernels of pi_2 and pi_1) are not submodules:: sage: R.annihilator_with_apex(W([2,1,3,4])) Vector space of degree 3 and dimension 2 over Rational Field Basis matrix: [ 1 -1 0] [ 0 0 1] sage: R.annihilator_with_apex(W([1,3,2,4])) Vector space of degree 3 and dimension 2 over Rational Field Basis matrix: [ 1 0 -1] [ 0 1 0] Could the map J -> R.annihilator_module_with_apexAnn(J) be extended to a morphism of posets from the poset of regular J-classes? Then, the pair of maps: J \mapsto self.annihilator_module_with_apex(J) and A \mapsto A.apex() should give a Galois connection. """ S = self.semigroup() AnnJ = self.annihilator_with_apex(J) # If the apex of AnnJ is not J if all(self.action(s, self.from_vector(x)).is_zero() for x in AnnJ.basis() for s in S.regular_j_class_semigroup_generators(J)): return None # If AnnJ is a submodule if any(self.action(s, self.from_vector(x)).to_vector() not in AnnJ for x in AnnJ.basis() for s in S.semigroup_generators()): return None # Problem: make sure that the subspace AnnJ is private to self assert not hasattr(AnnJ, 'apex') AnnJ.apex = ConstantFunction(J) return AnnJ @cached_method def composition_series(self): """ The (multiplicity-free) composition series of this module. This returns the set of (index of) `J`-classes `J` such that `J` is the apex of some submodule of ``self``. (conjectural: in fact only those such that there is an annihilator module with apex `J`) EXAMPLES:: sage: M = Semigroups().SetsWithAction().example().algebra(QQ); M Free module generated by Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication over Rational Field sage: M.composition_series() {0, 1} """ S = self.semigroup() R = self.basis().keys() try: I = R.apex() Js = [J for J in S.j_poset_on_regular_classes().principal_order_filter(I)] except AttributeError: Js = S.regular_j_classes_keys() from sage.sets.set import Set return Set(J for J in Js if self.annihilator_module_with_apex(J) is not None) @cached_method def composition_series_poset(self): """ The composition series of this module, endowed with `J`-order. EXAMPLES:: sage: M = Semigroups().SetsWithAction().example().algebra(QQ); M Free module generated by Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication over Rational Field sage: M.composition_series_poset() Finite poset containing 2 elements sage: M.composition_series_poset().cover_relations() [[1, 0]] """ S = self.semigroup() P = S.j_poset_on_regular_classes() return P.subposet(list(self.composition_series())) def annihilator_poset(self): """ This computes all annihilator submodules with apex of ``self`` (see :meth:`self.annihilator_module_with_apex`) and order them for inclusion. EXAMPLES:: sage: M = Semigroups().SetsWithAction().example().algebra(QQ); M Free module generated by Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication over Rational Field sage: M.annihilator_poset() Finite poset containing 2 elements sage: M.annihilator_poset().cover_relations() [[Vector space of degree 10 and dimension 5 over Rational Field Basis matrix: [ 1 0 0 0 0 -1 0 0 0 0] [ 0 1 0 0 0 0 -1 0 0 0] [ 0 0 1 0 0 0 0 -1 0 0] [ 0 0 0 1 0 0 0 0 -1 0] [ 0 0 0 0 1 0 0 0 0 -1], Vector space of degree 10 and dimension 10 over Rational Field Basis matrix: [1 0 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0] [0 0 0 0 0 0 1 0 0 0] [0 0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 0 0 1]]] """ from sage.combinat.posets.posets import Poset return Poset([[self.annihilator_with_apex(J) for J in self.composition_series()], lambda M, N: M.is_subspace(N)]) @cached_method def test_composition_series_poset(self): """ Sanity checks for a for regular left/right class EXAMPLES:: sage: M = Semigroups().SetsWithAction().example().algebra(QQ); M Free module generated by Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication over Rational Field sage: M.test_composition_series_poset() """ S = self.semigroup() R = self.basis().keys() composition_series_poset = self.composition_series_poset() assert composition_series_poset.is_meet_semilattice() #annihilator_poset = self.annihilator_poset() #annihilator_poset_dual = annihilator_poset.dual() #f = lambda J: annihilator_poset_dual(self.annihilator_with_apex(J)) #assert composition_series_poset.is_poset_isomorphism(f, annihilator_poset_dual) # Dimension checks for J in self.composition_series(): assert self.annihilator_with_apex(J).dimension() == S.lr_regular_class(J, side=R.side()).cardinality() assert self.dimension() == sum(S.simple_module_dimension(J) for J in self.composition_series()) # That can't work with the current definition of annihilator_module_with_apex. # j_poset = S.j_poset_on_regular_classes() # f = lambda J: composition_series_poset(self.annihilator_module_with_apex(J).apex()) # assert j_poset.is_poset_morphism(f, composition_series_poset) return assert composition_series_poset.is_lattice() from sage.combinat.posets.lattices import LatticePoset composition_lattice = LatticePoset(composition_series_poset) # annihilator_poset = LatticePoset(annihilator_poset) # Check that self.annihilator_module_with_apex is a # lattice morphism from the composition poset to the # lattice of submodules of self. This is similar to # the above isomorphism test with the # annihilator_poset, except that we enforce that the # meet on submodules is given by intersection. f = lambda J: self.annihilator_module_with_apex(J) L = composition_lattice for J1 in self.composition_series(): for J2 in self.composition_series(): assert f(J1).intersection(f(J2)) == f( L.join(L(J1), L(J2)) )
class ParentMethods: r""" TESTS: Ideally, these tests should be just after the declaration of the associated attributes. But doing this way, Sage will not consider them as a doctest. We check that Cartesian products of finite enumerated sets inherit various methods from `Sets.CartesianProducts` and not from :class:`EnumeratedSets.Finite`:: sage: C = cartesian_product([Partitions(10), Permutations(20)]) sage: C in EnumeratedSets().Finite() True sage: C.random_element.__module__ 'sage.categories.sets_cat' sage: C.cardinality.__module__ 'sage.categories.sets_cat' sage: C.__iter__.__module__ 'sage.categories.sets_cat' """ random_element = raw_getattr(Sets.CartesianProducts.ParentMethods, "random_element") cardinality = raw_getattr(Sets.CartesianProducts.ParentMethods, "cardinality") __iter__ = raw_getattr(Sets.CartesianProducts.ParentMethods, "__iter__") def last(self): r""" Return the last element EXAMPLES:: sage: C = cartesian_product([Zmod(42), Partitions(10), IntegerRange(5)]) sage: C.last() (41, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 4) """ return self._cartesian_product_of_elements( tuple(c.last() for c in self.cartesian_factors())) def rank(self, x): r""" Return the rank of an element of this Cartesian product. The *rank* of ``x`` is its position in the enumeration. It is an integer between ``0`` and ``n-1`` where ``n`` is the cardinality of this set. .. SEEALSO:: - :meth:`EnumeratedSets.ParentMethods.rank` - :meth:`unrank` EXAMPLES:: sage: C = cartesian_product([GF(2), GF(11), GF(7)]) sage: C.rank(C((1,2,5))) 96 sage: C.rank(C((0,0,0))) 0 sage: for c in C: print(C.rank(c)) 0 1 2 3 4 5 ... 150 151 152 153 sage: F1 = FiniteEnumeratedSet('abcdefgh') sage: F2 = IntegerRange(250) sage: F3 = Partitions(20) sage: C = cartesian_product([F1, F2, F3]) sage: c = C(('a', 86, [7,5,4,4])) sage: C.rank(c) 54213 sage: C.unrank(54213) ('a', 86, [7, 5, 4, 4]) """ from builtins import zip from sage.rings.integer_ring import ZZ x = self(x) b = ZZ.one() rank = ZZ.zero() for f, c in zip(reversed(x.cartesian_factors()), reversed(self.cartesian_factors())): rank += b * c.rank(f) b *= c.cardinality() return rank def unrank(self, i): r""" Return the ``i``-th element of this Cartesian product. INPUT: - ``i`` -- integer between ``0`` and ``n-1`` where ``n`` is the cardinality of this set. .. SEEALSO:: - :meth:`EnumeratedSets.ParentMethods.unrank` - :meth:`rank` EXAMPLES:: sage: C = cartesian_product([GF(3), GF(11), GF(7), GF(5)]) sage: c = C.unrank(123); c (0, 3, 3, 3) sage: C.rank(c) 123 sage: c = C.unrank(857); c (2, 2, 3, 2) sage: C.rank(c) 857 sage: C.unrank(2500) Traceback (most recent call last): ... IndexError: index i (=2) is greater than the cardinality """ from sage.rings.integer_ring import ZZ i = ZZ(i) if i < 0: raise IndexError("i (={}) must be a non-negative integer") elt = [] for c in reversed(self.cartesian_factors()): card = c.cardinality() elt.insert(0, c.unrank(i % card)) i //= card if i: raise IndexError("index i (={}) is greater than the cardinality".format(i)) return self._cartesian_product_of_elements(elt)
class Algebras(AlgebrasCategory): # see the warning in sage.categories.set_with_action_functor.SetsWithActionCategory._algebras_extra_super_categories extra_super_categories = raw_getattr( SetsWithActionCategory, "_algebras_extra_super_categories")
class ParentMethods: __init_extra__ = raw_getattr( Groups.Finite.Algebras.ParentMethods, "__init_extra__")
class ParentMethods: group = raw_getattr(Groups.Algebras.ParentMethods, "group")
def trace_method(obj, meth, **kwds): r""" Trace the doings of a given method. It prints method entry with arguments, access to members and other methods during method execution as well as method exit with return value. INPUT: - ``obj`` -- the object containing the method. - ``meth`` -- the name of the method to be traced. - ``prefix`` -- (default: ``" "``) string to prepend to each printed output. - ``reads`` -- (default: ``True``) whether to trace read access as well. EXAMPLES:: sage: class Foo(object): ....: def f(self, arg=None): ....: self.y = self.g(self.x) ....: if arg: return arg*arg ....: def g(self, arg): ....: return arg + 1 ....: sage: foo = Foo() sage: foo.x = 3 sage: from sage.doctest.fixtures import trace_method sage: trace_method(foo, "f") sage: foo.f() enter f() read x = 3 call g(3) -> 4 write y = 4 exit f -> None sage: foo.f(3) enter f(3) read x = 3 call g(3) -> 4 write y = 4 exit f -> 9 9 """ from sage.cpython.getattr import raw_getattr f = raw_getattr(obj, meth) t = AttributeAccessTracerProxy(obj, **kwds) @wraps(f) def g(*args, **kwds): arglst = [reproducible_repr(arg) for arg in args] arglst.extend("{}={}".format(k, reproducible_repr(v)) for k, v in sorted(kwds.items())) print("enter {}({})".format(meth, ", ".join(arglst))) res = f(t, *args, **kwds) print("exit {} -> {}".format(meth, reproducible_repr(res))) return res setattr(obj, meth, g)