diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index 62ff402d522..f02afe1dfaa 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -49,10 +49,16 @@ # finite groups/... from .finite_semigroups import FiniteSemigroups -from .finite_monoids import FiniteMonoids from .finite_groups import FiniteGroups from .finite_permutation_groups import FinitePermutationGroups +#monoids/... +from .finite_monoids import FiniteMonoids +from .h_trivial_monoids import HTrivialMonoids +from .r_trivial_monoids import RTrivialMonoids +from .l_trivial_monoids import LTrivialMonoids +from .j_trivial_monoids import JTrivialMonoids + # fields from .number_fields import NumberFields from .function_fields import FunctionFields diff --git a/src/sage/categories/examples/finite_semigroups.py b/src/sage/categories/examples/finite_semigroups.py index 306775ce53e..7b879c351f6 100644 --- a/src/sage/categories/examples/finite_semigroups.py +++ b/src/sage/categories/examples/finite_semigroups.py @@ -1,12 +1,12 @@ """ Examples of finite semigroups """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.sets.family import Family @@ -103,7 +103,7 @@ class LeftRegularBand(UniqueRepresentation, Parent): running ._test_some_elements() . . . pass """ - def __init__(self, alphabet=('a','b','c','d')): + def __init__(self, alphabet=('a', 'b', 'c', 'd'), category=None): r""" A left regular band. @@ -116,7 +116,9 @@ def __init__(self, alphabet=('a','b','c','d')): sage: TestSuite(S).run() """ self.alphabet = alphabet - Parent.__init__(self, category = Semigroups().Finite().FinitelyGenerated()) + if category is None: + category = Semigroups().Finite().FinitelyGenerated() + Parent.__init__(self, category=category) def _repr_(self): r""" @@ -126,7 +128,7 @@ def _repr_(self): sage: S._repr_() "An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c', 'd')" """ - return "An example of a finite semigroup: the left regular band generated by %s"%(self.alphabet,) + return "An example of a finite semigroup: the left regular band generated by %s" % (self.alphabet,) def product(self, x, y): r""" diff --git a/src/sage/categories/finite_semigroups.py b/src/sage/categories/finite_semigroups.py index 76c082af096..52c6e617319 100644 --- a/src/sage/categories/finite_semigroups.py +++ b/src/sage/categories/finite_semigroups.py @@ -134,3 +134,4 @@ def first_idempotent(l): # TODO: compute eJe, where J is the J-class of e # TODO: construct the action of self on it, as a permutation group + # TODO: Construct ideals of semigroups, ie R(a) = aS, L(a) = Sa, J(a) = SaS. diff --git a/src/sage/categories/h_trivial_monoids.py b/src/sage/categories/h_trivial_monoids.py new file mode 100644 index 00000000000..209dd03927d --- /dev/null +++ b/src/sage/categories/h_trivial_monoids.py @@ -0,0 +1,60 @@ +from sage.misc.cachefunc import cached_method +from sage.categories.monoids import Monoids +from sage.categories.category import Category +from sage.categories.category_with_axiom import CategoryWithAxiom + + +class HTrivialMonoids(Category): + """ + The category of `H`-trivial monoids + + Let `M` be a monoid. The `H`-*preorder* is defined by `x\leq_H y` + if `x \in My` and `x \in yM`. The `H`-*classes* are the + equivalence classes for the associated equivalence relation. A + monoid is `H`-*trivial* if all its `H`-classes are trivial, that + is of cardinality `1`, or equivalently if the `H`-preorder is in + fact an order. + + A `H`-trivial monoid is also called an aperiodic monoid. + + See :wikipedia:`Aperiodic_semigroup` + + EXAMPLES:: + + sage: from sage.categories.h_trivial_monoids import * + sage: C = HTrivialMonoids(); C + Category of h trivial monoids + sage: C.super_categories() + [Category of monoids] + sage: C.example() + NotImplemented + + .. seealso:: :class:`LTrivialMonoids`, :class:`RTrivialMonoids`, :class:`JTrivialMonoids` + """ + + @cached_method + def super_categories(self): + """ + + """ + return [Monoids()] + + class Finite(CategoryWithAxiom): + + class ParentMethods: + pass + + class ElementMethods: + + def pow_omega(self): + """ + The omega power of ``self``. + """ + res_old = self + res_new = res_old * res_old + while res_old != res_new: + res_old = res_new + res_new = res_old * res_old + return res_new + + pow_infinity = pow_omega # for backward compatibility diff --git a/src/sage/categories/j_trivial_monoids.py b/src/sage/categories/j_trivial_monoids.py new file mode 100644 index 00000000000..f59aa79c718 --- /dev/null +++ b/src/sage/categories/j_trivial_monoids.py @@ -0,0 +1,79 @@ +r""" +Finite J-Trivial Monoids +""" +#***************************************************************************** +# Copyright (C) 2009-2010 Florent Hivert +# 2009-2010 Nicolas M. Thiery +# +# Distributed under the terms of the GNU General Public License (GPL) +# http://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.categories.category import Category +from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.categories.l_trivial_monoids import LTrivialMonoids +from sage.categories.r_trivial_monoids import RTrivialMonoids +from sage.misc.cachefunc import cached_in_parent_method +from sage.sets.family import Family + + +class JTrivialMonoids(Category): + r""" + The category of `J`-trivial monoids + + Let `M` be a monoid. The `J`-relation on `M` is given by + `a \sim b iff MaM = MbM`. A monoid is `J`-trivial if all its `J`-classes + are of cardinality one. + """ + + @cached_method + def super_categories(self): + return [LTrivialMonoids(), RTrivialMonoids()] + + class Finite(CategoryWithAxiom): + """ + The category of finite `J`-trivial monoids + """ + class ParentMethods: + + @cached_method + def semigroup_generators(self): + """ + Returns the canonical minimal set of generators. It + consists of the irreducible elements, that is elements + which are not of the form `x*y` with `x` and `y` in + ``self`` distinct from `x*y`. + """ + res = [] + G = self.cayley_graph(side="twosided") + for x in G: + if x == self.one().value: + continue + incoming = set(G.incoming_edges(x)) + if all(l == x for u, v, l in incoming): + res.append(self(x)) + return Family(res) + + class ElementMethods: + + @cached_in_parent_method + def symbol(self, side="left"): + """ + Return the unique minimal idempotent `e` (in J-order) + such that `e x = x` (resp. `xe = x`). + + INPUT: + + - ``self`` -- a monoid element `x` + - ``side`` -- "left", "right" + """ + monoid = self.parent() + + if side == "left": + fix = [s for s in monoid.semigroup_generators() + if s * self == self] + else: + fix = [s for s in monoid.semigroup_generators() + if self * s == self] + return (monoid.prod(fix)).pow_omega() diff --git a/src/sage/categories/l_trivial_monoids.py b/src/sage/categories/l_trivial_monoids.py new file mode 100644 index 00000000000..6df95c63fee --- /dev/null +++ b/src/sage/categories/l_trivial_monoids.py @@ -0,0 +1,70 @@ +from sage.misc.cachefunc import cached_method +from sage.categories.category import Category +from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.categories.h_trivial_monoids import HTrivialMonoids + + +class LTrivialMonoids(Category): + """ + The category of `L`-trivial monoids + + Let `M` be a monoid. The `L`-*preorder* is defined by `x\leq_L y` + if `x \in My`. The `L`-*classes* are the equivalence classes + for the associated equivalence relation. A monoid is `L`-*trivial* + if all its `L`-classes are trivial, that is of cardinality `1`, or + equivalently if the `L`-preorder is in fact an order. + + EXAMPLES:: + + sage: C = LTrivialMonoids(); C + Category of l trivial monoids + sage: C.super_categories() + [Category of h trivial monoids] + + .. seealso:: :class:`RTrivialMonoids`, :class:`HTrivialMonoids`, :class:`JTrivialMonoids` + """ + + @cached_method + def super_categories(self): + """ + EXAMPLES: + + An L-trivial monoid is also H-trivial:: + + sage: LTrivialMonoids().super_categories() + [Category of h trivial monoids] + """ + return [HTrivialMonoids()] + + class Finite(CategoryWithAxiom): + + class ParentMethods: + + def index_of_regular_j_class(self, idempotent): + """ + Return the index that should be used for an idempotent in the transversal. + + In this implementation, each idempotent e is indexed + by the subset of the indices `i` of the generators + `s_i` such that `es_i=e` (that is `s_i` acts by `1` on + the corresponding simple module). + + .. seealso:: :meth:`FiniteSemigroups.ParentMethods.j_transversal_of_idempotents` + + .. TODO:: + + This is mostly a duplicate of + :meth:`RTrivialMonoids.Finite.ParentMethods.j_transversal_of_idempotents` + + Instead this should be generalized to + DASemigroups.Finite, by testing if idempotent * + s[i] is in the same J-class. And recycled to build + the corresponding simple module. + + EXAMPLES:: + + sage: TODO! + """ + s = self.semigroup_generators() + return tuple(i for i in s.keys() + if s[i] * idempotent == idempotent) diff --git a/src/sage/categories/r_trivial_monoids.py b/src/sage/categories/r_trivial_monoids.py new file mode 100644 index 00000000000..aaaea1e6b36 --- /dev/null +++ b/src/sage/categories/r_trivial_monoids.py @@ -0,0 +1,98 @@ +# **************************************************************************** +# Copyright (C) 2009-2010 Florent Hivert +# 2009-2010 Nicolas M. Thiery +# +# Distributed under the terms of the GNU General Public License (GPL) +# https://www.gnu.org/licenses/ +# ***************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.categories.category import Category +from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.categories.h_trivial_monoids import HTrivialMonoids + + +class RTrivialMonoids(Category): + """ + The category of `R`-trivial monoids + + Let `M` be a monoid. The `R`-*preorder* is defined by `x\leq_R y` + if `x \in yM`. The `R`-*classes* are the equivalence classes + for the associated equivalence relation. A monoid is `R`-*trivial* + if all its `R`-classes are trivial, that is of cardinality `1`, or + equivalently if the `R`-preorder is in fact an order. + + EXAMPLES:: + + sage: C = RTrivialMonoids(); C + Category of r trivial monoids + sage: C.super_categories() + [Category of h trivial monoids] + + .. SEEALSO:: :class:`LTrivialMonoids`, :class:`HTrivialMonoids`, :class:`JTrivialMonoids` + """ + + @cached_method + def super_categories(self): + """ + EXAMPLES: + + An R-trivial monoid is also H-trivial:: + + sage: RTrivialMonoids().super_categories() + [Category of h trivial monoids] + """ + return [HTrivialMonoids()] + + def example(self, alphabet=('a', 'b', 'c')): + """ + Return an example of (finite) right trivial monoid. + + .. SEEALSO:: :meth:`Category.example` + + .. TODO:: this cheating a bit: this is just a semigroup, not a monoid! + + EXAMPLES:: + + sage: S = RTrivialMonoids().example(); S + An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c') + sage: S.category() + Category of finitely generated finite enumerated r trivial monoids + """ + from sage.categories.examples.finite_semigroups import LeftRegularBand + return LeftRegularBand(alphabet=alphabet, + category=RTrivialMonoids().Finite().FinitelyGenerated()) + + class Finite(CategoryWithAxiom): + + class ParentMethods: + + def index_of_regular_j_class(self, idempotent): + """ + Return the index that should be used for an idempotent in the transversal. + + In this implementation, each idempotent e is indexed + by the subset of the indices `i` of the generators + `s_i` such that `es_i=e` (that is `s_i` acts by `1` on + the corresponding simple module). + + .. SEEALSO:: :meth:`FiniteSemigroups.ParentMethods.j_transversal_of_idempotents` + + EXAMPLES:: + + sage: S = RTrivialMonoids().example(alphabet=('a','b','c')); S + An example of a finite semigroup: the left regular band generated by ('a', 'b', 'c') + sage: S.category() + Category of finitely generated finite enumerated r trivial monoids + sage: a,b,c = S.semigroup_generators() + sage: S.index_of_regular_j_class(a*c) + (0, 2) + + This is used to index the transversal of idempotents:: + + sage: sorted(S.j_transversal_of_idempotents()) + ['a', 'ab', 'abc', 'ac', 'b', 'bc', 'c'] + """ + s = self.semigroup_generators() + return tuple(i for i in s.keys() + if idempotent * s[i] == idempotent) diff --git a/src/sage/combinat/j_trivial_monoids.py b/src/sage/combinat/j_trivial_monoids.py new file mode 100644 index 00000000000..e45f3c0bdc8 --- /dev/null +++ b/src/sage/combinat/j_trivial_monoids.py @@ -0,0 +1,140 @@ +from sage.categories.j_trivial_monoids import JTrivialMonoids +from sage.matrix.constructor import Matrix +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element_wrapper import ElementWrapper +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.sets.family import Family +from itertools import product + + +""" +Implement the monoid of Unitriangular Boolean matrices, which is J-trivial +""" +class UnitriangularBooleanMatrices(Parent, UniqueRepresentation): + + def __init__(self, n): + self.n = n + Parent.__init__(self, category=JTrivialMonoids().Finite()) + + def _repr_(self): + """ + EXAMPLES:: + + sage: from sage.combinat.j_trivial_monoids import UnitriangularBooleanMatrices + sage: UnitriangularBooleanMatrices(4) + Monoid of Unitriangular Boolean Matrices 4 x 4 + """ + return "Monoid of Unitriangular Boolean Matrices %s x %s"%(self.n, self.n) + + @cached_method + def one(self): + """ + Return the identity element of the monoid ``self`` + """ + M = Matrix(GF(2), self.n, self.n, lambda i, j: i == j) + M.set_immutable() + return self(M) + + def product(self, right, left): + """ + Return the product of the elements ``left`` and ``right`` in ``self`` + + EXAMPLES:: + + sage: from sage.combinat.j_trivial_monoids import UnitriangularBooleanMatrices + sage: U4 = UnitriangularBooleanMatrices(4) + sage: a = U4(Matrix(GF(2), 4, 4, [[1,0,1,1],[0,1,1,0],[0,0,1,1],[0,0,0,1]])) + sage: b = U4(Matrix(GF(2), 4, 4, [[1,1,0,1],[0,1,0,0],[0,0,1,1],[0,0,0,1]])) + sage: a * b + [1 1 1 1] + [0 1 1 1] + [0 0 1 1] + [0 0 0 1] + sage: b * a + [1 1 1 1] + [0 1 1 0] + [0 0 1 1] + [0 0 0 1] + """ + M = Matrix(GF(2), self.n, self.n, + lambda i, j: right.value[i][j] or + left.value[i][j] or + any(right.value[i][k] and left.value[k][j] + for k in range(self.n))) + M.set_immutable() + return self(M) + + def semigroup_generators(self): + """ + Return the generating family of the monoid ``self``, namely all + unitriangular boolean matrices with n+1 1s + + .. TODO:: + + Make immutable matrices in an easier way... This method should + be only one line. + + EXAMPLES:: + + sage: from sage.combinat.j_trivial_monoids import UnitriangularBooleanMatrices + sage: U4 = UnitriangularBooleanMatrices(4) + sage: len(U4.semigroup_generators()) + 16 + """ + res = [Matrix(GF(2), self.n, self.n, + lambda i, j: (i == j) or (i <= j and (i == k and j == l))) for k,l in + product(range(self.n), range(self.n))] + for M in res: + M.set_immutable() + + return Family(self(M) for M in res) + + def cardinality(self): + """ + Return the cardinality of ``self`` + + EXAMPLES:: + + sage: from sage.combinat.j_trivial_monoids import UnitriangularBooleanMatrices + sage: UnitriangularBooleanMatrices(6).cardinality() + 32768 + """ + return 2 ** ((self.n ** 2 - self.n) // 2) + + def _an_element_(self): + """ + Return an element of ``self`` + """ + return self.one() + + def random_element(self): + """ + Return a random element of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.j_trivial_monoids import UnitriangularBooleanMatrices + sage: U = UnitriangularBooleanMatrices(5) + sage: U.an_element() # random + [1 1 0 0 0] + [0 1 0 1 1] + [0 0 1 1 1] + [0 0 0 1 0] + [0 0 0 0 1] + sage: U.an_element() # random + [1 0 0 1 0] + [0 1 1 1 0] + [0 0 1 1 0] + [0 0 0 1 0] + [0 0 0 0 1] + """ + from sage.misc.prandom import random + M = Matrix(GF(2), self.n, self.n, + lambda i, j: (i <= j) and ((i == j) or (random()<.5))) + M.set_immutable() + return self(M) + + class Element(ElementWrapper): + wrapped_class = Matrix