def quiver(self, edge_labels=True, index=False):
            """
            Returns the quiver of ``self``

            INPUT:

             - ``edges_labels`` -- whether to use the quiver element
               as label for the edges between the idempotents; if
               False, this may lead to multiple edges when the monoid
               is not generated by idempotents (default: True)

             - ``index`` -- whether to index the vertices of the graph
               by the indices of the simple modules rather than the
               corresponding idempotents (default: False)

            OUTPUT: the quiver of ``self``, as a graph with the
            idempotents of this monoid as vertices

            .. todo:: should index default to True?

            .. todo:: use a meaningful example

            EXAMPLES::

                sage: import sage_semigroups.monoids.catalog as semigroups
                sage: M = semigroups.NDPFMonoidPoset(Posets(3)[3])
                sage: G = M.quiver()
                sage: G
                Digraph on 4 vertices
                sage: G.edges()
                [([1], [2], [3])]
                sage: M.quiver(edge_labels=False).edges()
                [([1], [2], None)]
                sage: M.quiver(index=True).edges()
                [(2, 1, [3])]
                sage: M.quiver(index=True, edge_labels=False).edges()
                [(2, 1, None)]
            """
            from sage.graphs.graph import DiGraph
            res  = DiGraph()
            if index:
                res.add_vertices(self.simple_modules_index_set())
                symbol = attrcall("symbol_index")
            else:
                res.add_vertices(self.idempotents())
                symbol = attrcall("symbol")
            for x in self.quiver_elements():
                res.add_edge(symbol(x,"left"), symbol(x, "right"), x if edge_labels else None)
            return res
Example #2
0
        def quiver(self, edge_labels=True, index=False):
            """
            Returns the quiver of ``self``

            INPUT:

             - ``edges_labels`` -- whether to use the quiver element
               as label for the edges between the idempotents; if
               False, this may lead to multiple edges when the monoid
               is not generated by idempotents (default: True)

             - ``index`` -- whether to index the vertices of the graph
               by the indices of the simple modules rather than the
               corresponding idempotents (default: False)

            OUTPUT: the quiver of ``self``, as a graph with the
            idempotents of this monoid as vertices

            .. todo:: should index default to True?

            .. todo:: use a meaningful example

            EXAMPLES::

                sage: import sage_semigroups.monoids.catalog as semigroups
                sage: M = semigroups.NDPFMonoidPoset(Posets(3)[3])
                sage: G = M.quiver()
                sage: G
                Digraph on 4 vertices
                sage: G.edges()
                [([1], [2], [3])]
                sage: M.quiver(edge_labels=False).edges()
                [([1], [2], None)]
                sage: M.quiver(index=True).edges()
                [(2, 1, [3])]
                sage: M.quiver(index=True, edge_labels=False).edges()
                [(2, 1, None)]
            """
            from sage.graphs.graph import DiGraph
            res  = DiGraph()
            if index:
                res.add_vertices(self.simple_modules_index_set())
                symbol = attrcall("symbol_index")
            else:
                res.add_vertices(self.idempotents())
                symbol = attrcall("symbol")
            for x in self.quiver_elements():
                res.add_edge(symbol(x,"left"), symbol(x, "right"), x if edge_labels else None)
            return res
Example #3
0
def test_attrcall(name, L):
    """
    Return a function by name.

    This is a helper function for test_finite_lattice(). This
    will unify all Boolean-valued functions to a function without
    parameters.

    EXAMPLES::

        sage: from sage.tests.finite_poset import test_attrcall
        sage: N5 = posets.PentagonPoset()
        sage: N5.is_modular() == test_attrcall('is_modular', N5)
        True
        sage: N5.is_constructible_by_doublings('convex') == test_attrcall('is_doubling_convex', N5)
        True
    """
    from sage.misc.misc import attrcall
    if name == 'is_doubling_any':
        return L.is_constructible_by_doublings('any')
    if name == 'is_doubling_lower':
        return L.is_constructible_by_doublings('upper')
    if name == 'is_doubling_upper':
        return L.is_constructible_by_doublings('lower')
    if name == 'is_doubling_convex':
        return L.is_constructible_by_doublings('convex')
    if name == 'is_doubling_interval':
        return L.is_constructible_by_doublings('interval')
    if name == 'is_uniq_orthocomplemented':
        return L.is_orthocomplemented(unique=True)
    return attrcall(name)(L)
Example #4
0
def symmetric_derivatives(list_deg, row_symmetry=None):
    """
    Return the symmetric derivative functions for the 
    degree listed in `list_deg`.
    
    INPUT:
    - `r` -- a integer
    - `list_deg` -- a list of tuples
    - `row_symmetry` -- "permutation" (only implemented case)
    
    EXAMPLES::
        sage: list_deg = [(i,j) for i in range(3) for j in range(3) if i+j>0]
        sage: list_deg
        [(0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
        sage: symmetric_derivatives(list_deg)
        {(-2, -2): [*.symmetric_derivative(row_symmetry=None, d=(2, 2))],
         (-2, -1): [*.symmetric_derivative(row_symmetry=None, d=(2, 1))],
         (-2, 0): [*.symmetric_derivative(row_symmetry=None, d=(2, 0))],
         (-1, -2): [*.symmetric_derivative(row_symmetry=None, d=(1, 2))],
         (-1, -1): [*.symmetric_derivative(row_symmetry=None, d=(1, 1))],
         (-1, 0): [*.symmetric_derivative(row_symmetry=None, d=(1, 0))],
         (0, -2): [*.symmetric_derivative(row_symmetry=None, d=(0, 2))],
         (0, -1): [*.symmetric_derivative(row_symmetry=None, d=(0, 1))]}
    """
    r = len(list_deg[0])
    D = cartesian_product([ZZ for i in range(r)])
    return {
        D(-i for i in d):
        [attrcall("symmetric_derivative", d=d, row_symmetry=row_symmetry)]
        for d in list_deg
    }
Example #5
0
def fill_allignment_database(cls):
    """
    Fill the database mapping gap categories / properties to their
    corresponding (super) Sage categories from the semantic
    information stored in the category class
    """
    assert issubclass(cls, Category)

    gap = cls._semantic.get("gap")
    gap_sub = cls._semantic.get("gap_sub", gap)
    gap_negation = cls._semantic.get("gap_negation")
    if gap_sub is not None:
        gap_category_to_structure[gap_sub] = attrcall("add_category", cls)
    if gap_negation is not None:
        false_properties_to_structure[gap_negation] = attrcall(
            "add_category", cls)
Example #6
0
def test_attrcall(name, L):
    """
    Return a function by name.

    This is a helper function for test_finite_lattice(). This
    will unify all Boolean-valued functions to a function without
    parameters.

    EXAMPLES::

        sage: from sage.tests.finite_poset import test_attrcall
        sage: N5 = posets.PentagonPoset()
        sage: N5.is_modular() == test_attrcall('is_modular', N5)
        True
        sage: N5.is_constructible_by_doublings('convex') == test_attrcall('is_doubling_convex', N5)
        True
    """
    if name == 'is_doubling_any':
        return L.is_constructible_by_doublings('any')
    if name == 'is_doubling_lower':
        return L.is_constructible_by_doublings('upper')
    if name == 'is_doubling_upper':
        return L.is_constructible_by_doublings('lower')
    if name == 'is_doubling_convex':
        return L.is_constructible_by_doublings('convex')
    if name == 'is_doubling_interval':
        return L.is_constructible_by_doublings('interval')
    if name == 'is_uniq_orthocomplemented':
        return L.is_orthocomplemented(unique=True)
    return attrcall(name)(L)
Example #7
0
        def order_ideals_lattice(self):
            r"""
            Returns the lattice of order ideals of a poset `P`,
            ordered by inclusion. The usual notation is `J(P)`.

            EXAMPLES::

                sage: P = Posets.PentagonPoset(facade = True)
                sage: P.cover_relations()
                [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]]
                sage: J = P.order_ideals_lattice(); J
                Finite lattice containing 8 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 2, 3}, {0, 1, 2, 3}, {0, 1, 2, 3, 4}]

            TESTS::

                sage: J = Posets.DiamondPoset(4, facade = True).order_ideals_lattice(); J
                Finite lattice containing 6 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}]
                sage: J.cover_relations()
                [[{}, {0}], [{0}, {0, 2}], [{0}, {0, 1}], [{0, 2}, {0, 1, 2}], [{0, 1}, {0, 1, 2}], [{0, 1, 2}, {0, 1, 2, 3}]]

            .. note:: we use facade posets in the examples above just
               to ensure a nicer ordering in the output.
            """
            from sage.misc.misc import attrcall
            from sage.sets.set import Set
            from sage.combinat.posets.lattices import LatticePoset
            ideals = [Set( self.order_ideal(antichain) ) for antichain in self.antichains()]
            return LatticePoset((ideals,attrcall("issubset")))
Example #8
0
        def order_ideals_lattice(self):
            r"""
            Returns the lattice of order ideals of a poset `P`,
            ordered by inclusion. The usual notation is `J(P)`.

            EXAMPLES::

                sage: P = Posets.PentagonPoset(facade = True)
                sage: P.cover_relations()
                [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]]
                sage: J = P.order_ideals_lattice(); J
                Finite lattice containing 8 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 2, 3}, {0, 1, 2, 3}, {0, 1, 2, 3, 4}]

            TESTS::

                sage: J = Posets.DiamondPoset(4, facade = True).order_ideals_lattice(); J
                Finite lattice containing 6 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}]
                sage: J.cover_relations()
                [[{}, {0}], [{0}, {0, 2}], [{0}, {0, 1}], [{0, 2}, {0, 1, 2}], [{0, 1}, {0, 1, 2}], [{0, 1, 2}, {0, 1, 2, 3}]]

            .. note:: we use facade posets in the examples above just
               to ensure a nicer ordering in the output.
            """
            from sage.misc.misc import attrcall
            from sage.sets.set import Set
            from sage.combinat.posets.lattices import LatticePoset
            ideals = [
                Set(self.order_ideal(antichain))
                for antichain in self.antichains()
            ]
            return LatticePoset((ideals, attrcall("issubset")))
Example #9
0
    def cartesian_projection(self, i):
        """
        Return the natural projection onto the `i`-th Cartesian
        factor of ``self`` as per
        :meth:`Sets.CartesianProducts.ParentMethods.cartesian_projection()
        <sage.categories.sets_cat.Sets.CartesianProducts.ParentMethods.cartesian_projection>`.

        INPUT:

        - ``i`` -- the index of a Cartesian factor of ``self``

        EXAMPLES::

            sage: C = Sets().CartesianProducts().example(); C
            The Cartesian product of (Set of prime numbers (basic implementation), An example of an infinite enumerated set: the non negative integers, An example of a finite enumerated set: {1,2,3})
            sage: x = C.an_element(); x
            (47, 42, 1)
            sage: pi = C.cartesian_projection(1)
            sage: pi(x)
            42

            sage: C.cartesian_projection('hey')
            Traceback (most recent call last):
            ...
            ValueError: i (=hey) must be in {0, 1, 2}
        """
        if i not in self._sets_keys():
            raise ValueError("i (={}) must be in {}".format(i, self._sets_keys()))
        return attrcall("cartesian_projection", i)
Example #10
0
        def order_ideals_lattice(self, as_ideals=True):
            r"""
            Returns the lattice of order ideals of a poset `P`,
            ordered by inclusion. The usual notation is `J(P)`.

            The underlying set is by default the set of order ideals
            of `P`. It can be alternatively chosen to be the set of
            antichains of `P`.

            INPUT:

            - ``as_ideals`` -- Boolean, if ``True`` (default) returns
              a poset on the set of order ideals, otherwise on the set
              of antichains

            EXAMPLES::

                sage: P = Posets.PentagonPoset(facade = True)
                sage: P.cover_relations()
                [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]]
                sage: J = P.order_ideals_lattice(); J
                Finite lattice containing 8 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 2, 3}, {0, 1, 2, 3}, {0, 1, 2, 3, 4}]

            As a lattice on antichains::

                sage: J2 = P.order_ideals_lattice(False); J2
                Finite lattice containing 8 elements
                sage: list(J2)
                [(0,), (1, 2), (1, 3), (1,), (2,), (3,), (4,), ()]

            TESTS::

                sage: J = Posets.DiamondPoset(4, facade = True).order_ideals_lattice(); J
                Finite lattice containing 6 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}]
                sage: J.cover_relations()
                [[{}, {0}], [{0}, {0, 2}], [{0}, {0, 1}], [{0, 2}, {0, 1, 2}], [{0, 1}, {0, 1, 2}], [{0, 1, 2}, {0, 1, 2, 3}]]

            .. NOTE:: we use facade posets in the examples above just
               to ensure a nicer ordering in the output.
            """
            from sage.combinat.posets.lattices import LatticePoset
            if as_ideals:
                from sage.misc.misc import attrcall
                from sage.sets.set import Set
                ideals = [Set( self.order_ideal(antichain) ) for antichain in self.antichains()]
                return LatticePoset((ideals,attrcall("issubset")))
            else:
                from sage.misc.cachefunc import cached_function
                antichains = [tuple(a) for a in self.antichains()]
                @cached_function
                def is_above(a,xb):
                    return any(self.is_lequal(xa,xb) for xa in a)
                def cmp(a,b):
                    return all(is_above(a,xb) for xb in b)
                return LatticePoset((antichains,cmp))
Example #11
0
    def __reduce__(self):
        """
        TESTS::

            sage: CartanType(['F', 4, 1]).dual().__reduce__()
            (*.dual(), (['F', 4, 1],))
        """
        return (attrcall("dual"), (self._type,))
Example #12
0
    def __reduce__(self):
        """
        TESTS::

            sage: CartanType(['F', 4, 1]).dual().__reduce__()
            (*.dual(), (['F', 4, 1],))
        """
        return (attrcall("dual"), (self._type, ))
Example #13
0
def polarization_operators(r, max_deg=1, side=None, row_symmetry=None):
    """
    Return the polarization operator functions in `r` sets of variables with
    maximum degree `max_deg`.
    The polarization operator $P_{x,y}^k$ in defined by 
    $$P_{x,y}^k := \sum_i y_i \partial_{x_i}^k$$
    where X and y are two sets of variables and $\partial_{x_i}^k$ stand for 
    the $k$-th partial derivative in $x_i$.
    The option `side` allows to specify keywork "down" to return only polarization
    operators $P_{x_i,x_j}^k$ such that $i<j$. 
    
    INPUT:
    - `r` -- an integer
    - `max_deg` -- an integer
    - `row_symmetry` -- "permutation" (only implemented case)
    
    EXAMPLES::
        sage: polarization_operators(2)
        {(-1, 1): [*.polarization(i1=0, row_symmetry=None, i2=1, d=1)],
         (1, -1): [*.polarization(i1=1, row_symmetry=None, i2=0, d=1)]}
        sage: polarization_operators(2, max_deg=3)
        {(-3, 1): [*.polarization(i1=0, row_symmetry=None, i2=1, d=3)],
         (-2, 1): [*.polarization(i1=0, row_symmetry=None, i2=1, d=2)],
         (-1, 1): [*.polarization(i1=0, row_symmetry=None, i2=1, d=1)],
         (1, -3): [*.polarization(i1=1, row_symmetry=None, i2=0, d=3)],
         (1, -2): [*.polarization(i1=1, row_symmetry=None, i2=0, d=2)],
         (1, -1): [*.polarization(i1=1, row_symmetry=None, i2=0, d=1)]}
        sage: polarization_operators(2, max_deg=3, side="down")
        {(-3, 1): [*.polarization(i1=0, row_symmetry=None, i2=1, d=3)],
         (-2, 1): [*.polarization(i1=0, row_symmetry=None, i2=1, d=2)],
         (-1, 1): [*.polarization(i1=0, row_symmetry=None, i2=1, d=1)]}

        sage: v = vandermonde(Partition([2,1]), 2)
        sage: gen = {v.multidegree() : [v]}
        sage: op = partial_derivatives(v.parent())
        sage: S = Subspace(gen, op)
        sage: polarizators = polarization_operators(2, max_deg=v.degree())
        sage: Subspace(S.basis(), polarizators).basis()
        {(0, 0): (-theta00 + theta01, -theta00 + theta02),
         (0, 1): (-x11*theta00 + x12*theta00 + x10*theta01 - x12*theta01 - x10*theta02 + x11*theta02,),
         (1, 0): (x01*theta00 - x02*theta00 - x00*theta01 + x02*theta01 + x00*theta02 - x01*theta02,)}
    """
    D = cartesian_product([ZZ for i in range(r)])
    return {
        D([-d if i == i1 else 1 if i == i2 else 0 for i in range(r)]): [
            attrcall("polarization",
                     i1=i1,
                     i2=i2,
                     d=d,
                     row_symmetry=row_symmetry)
        ]
        for d in range(1, max_deg + 1) for i1 in range(0, r)
        for i2 in range(0, r) if (i1 < i2 if side == 'down' else i1 != i2)
    }
Example #14
0
def multipolarization(r, list_deg, i2, row_symmetry=None):
    """
    """
    D = cartesian_product([ZZ for i in range(r)])
    op = {}
    for deg in list_deg:
        op[D(-deg[i] + 1 if i == i2 else -deg[i] for i in range(len(deg)))] = [
            attrcall("multi_polarization",
                     D=deg,
                     i2=i2,
                     row_symmetry=row_symmetry)
        ]
    return op
Example #15
0
    def transition_module(self, alphabet=None, monoid=None, side="right"):
        r"""
        Constructs a transformation module whose Cayley graph is ``self``.

        INPUT:

        - ``alphabet`` -- a list of index of the operators (default:
          the set of labels of the edges of the graph)
        - ``monoid`` -- the monoid that is acting (default: the
          transition monoid of this automaton);
        - ``side`` -- 'left' or 'right' (default: 'right'); on which
          side the action is considered


        .. warning::

            At this point only the transition monoid is actually supported!
            One should support instead any monoid of whom the
            transition monoid is a quotient of, by going through
            reduced words.

        EXAMPLES::

            sage: automaton = DiGraph( [ (1, 1, "b"), (1, 2, "a"),
            ...                          (2, 2, "a"), (2, 2, "c"), (2, 3, "b"),
            ...                          (3, 2, "a"), (3, 3, "b"), (3, 3, "c") ] )
            sage: M = automaton.transition_module()
            sage: M.cayley_graph().edges() == automaton.edges()  # todo: not implemented (some edges are repeated!!!)
            True
            sage: set(M.cayley_graph().edges()) == set(automaton.edges())
            True

        Its semigroup is the transition monoid of ``self``::

            sage: M.semigroup()
            The transition monoid of Looped multi-digraph on 3 vertices
            sage: M.semigroup() is automaton.transition_monoid()
            True
            sage: TestSuite(M).run() # todo: several tests fail here
        """
        from sage.misc.misc import attrcall
        from sage.monoids.representations import SetWithAction
        if monoid is None:
            monoid = self.transition_monoid(alphabet=alphabet, side=side)
        else:
            assert monoid.automaton().vertices() == self.vertices()

        return SetWithAction(monoid,
                             self.vertices(),
                             attrcall("__call__"),
                             side=side)
Example #16
0
def category_graph(categories=None, relabel="object_names"):
    """
    Return the graph of the categories in Sage.

    INPUT:

    - ``categories`` -- a list (or iterable) of categories

    If ``categories`` is specified, then the graph contains the
    mentioned categories together with all their super
    categories. Otherwise the graph contains (an instance of) each
    category in :mod:`sage.categories.all` (e.g. ``Algebras(QQ)`` for
    algebras).

    For readability, the names of the category are shortened.

    .. TODO:: Further remove the base ring (see also :trac:`15801`).

    EXAMPLES::

        sage: G = sage.categories.category.category_graph(categories = [Groups()])
        sage: G.vertices()
        ['groups', 'inverse unital magmas', 'magmas', 'monoids', 'objects',
         'semigroups', 'sets', 'sets with partial maps', 'unital magmas']
        sage: G.plot()
        Graphics object consisting of 20 graphics primitives

        sage: sage.categories.category.category_graph().plot()
        Graphics object consisting of ... graphics primitives
    """
    from sage import graphs
    if categories is None:
        categories = category_sample()
    # Include all the super categories
    # Get rid of join categories
    categories = set(cat for category in categories
                     for cat in category.all_super_categories(
                         proper=isinstance(category, JoinCategory)))
    g = graphs.digraph.DiGraph()
    for cat in categories:
        g.add_vertex(cat)
        for source in categories:
            # Don't use super_categories() since it might contain join categories
            for target in source._super_categories:
                g.add_edge([source, target])

    if relabel == "object_names":
        g.relabel(attrcall("_repr_object_names"))
    return g
Example #17
0
        def j_classes_of_idempotents(self):
            r"""
            Returns all the idempotents of self, grouped by J-class.

            OUTPUT:

             a list of lists.

            EXAMPLES::

                sage: S = FiniteSemigroups().example(alphabet=('a','b', 'c'))
                sage: sorted(map(sorted, S.j_classes_of_idempotents()))
                [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']]
            """
            return [l for l in ([x for x in cl if attrcall('is_idempotent')(x)] for cl in self.j_classes()) if len(l) > 0]
Example #18
0
        def j_classes_of_idempotents(self):
            r"""
            Returns all the idempotents of self, grouped by J-class.

            OUTPUT:

             a list of lists.

            EXAMPLES::

                sage: S = FiniteSemigroups().example(alphabet=('a','b', 'c'))
                sage: sorted(map(sorted, S.j_classes_of_idempotents()))
                [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']]
            """
            return [l for l in ([x for x in cl if attrcall('is_idempotent')(x)] for cl in self.j_classes()) if len(l) > 0]
Example #19
0
    def transition_module(self, alphabet = None, monoid=None, side="right"):
        r"""
        Constructs a transformation module whose Cayley graph is ``self``.

        INPUT:

        - ``alphabet`` -- a list of index of the operators (default:
          the set of labels of the edges of the graph)
        - ``monoid`` -- the monoid that is acting (default: the
          transition monoid of this automaton);
        - ``side`` -- 'left' or 'right' (default: 'right'); on which
          side the action is considered


        .. warning::

            At this point only the transition monoid is actually supported!
            One should support instead any monoid of whom the
            transition monoid is a quotient of, by going through
            reduced words.

        EXAMPLES::

            sage: automaton = DiGraph( [ (1, 1, "b"), (1, 2, "a"),
            ...                          (2, 2, "a"), (2, 2, "c"), (2, 3, "b"),
            ...                          (3, 2, "a"), (3, 3, "b"), (3, 3, "c") ] )
            sage: M = automaton.transition_module()
            sage: M.cayley_graph().edges() == automaton.edges()  # todo: not implemented (some edges are repeated!!!)
            True
            sage: set(M.cayley_graph().edges()) == set(automaton.edges())
            True

        Its semigroup is the transition monoid of ``self``::

            sage: M.semigroup()
            The transition monoid of Looped multi-digraph on 3 vertices
            sage: M.semigroup() is automaton.transition_monoid()
            True
            sage: TestSuite(M).run() # todo: several tests fail here
        """
        from sage.misc.misc import attrcall
        from sage.monoids.representations import SetWithAction
        if monoid is None:
            monoid = self.transition_monoid(alphabet = alphabet, side=side)
        else:
            assert monoid.automaton().vertices() == self.vertices()

        return SetWithAction(monoid, self.vertices(), attrcall("__call__"), side=side)
Example #20
0
        def j_classes_of_idempotents(self):
            r"""
            Returns all the idempotents of self, grouped by J-class.

            OUTPUT:

             a list of lists.

            EXAMPLES::

                sage: S = FiniteSemigroups().example(alphabet=('a','b', 'c'))
                sage: sorted(map(sorted, S.j_classes_of_idempotents()))
                [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']]
            """
            return [
                l for l in map(lambda cl: list(filter(attrcall("is_idempotent"), cl)), self.j_classes()) if len(l) > 0
            ]
        def j_classes_of_idempotents(self):
            r"""
            Returns all the idempotents of self, grouped by J-class.

            OUTPUT:

             a list of lists.

            EXAMPLES::

                sage: S = FiniteSemigroups().example(alphabet=('a','b', 'c'))
                sage: sorted(map(sorted, S.j_classes_of_idempotents()))
                [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']]
            """
            return filter(lambda l: len(l) > 0,
                          map(lambda cl: filter(attrcall('is_idempotent'), cl),
                              self.j_classes()))
Example #22
0
def steenrod_operators(r, degree=1, row_symmetry=None):
    """
    Return the Steenrod operator functions in `r` sets of variables of 
    degree `degree`.
    The Steenrod operator $S_{x}^k$ in defined for $k>1$ by 
    $$S_{x}^k := \sum_i x_i \partial_{x_i}^k$$
    where X and y are two sets of variables and $\partial_{x_i}^k$ stand for 
    the $k$-th partial derivative in $x_i$.
    
    INPUT:
    - `r` -- a integer
    - `degree` -- an integer
    - `row_symmetry` -- "permutation" (only implemented case)
    
    EXAMPLES ::
        sage: steenrod_operators(2)
        {(-1, 0): [*.steenrod_op(i=0, row_symmetry=None, k=2)],
         (0, -1): [*.steenrod_op(i=1, row_symmetry=None, k=2)]}
        sage: steenrod_operators(2, 2)
        {(-2, 0): [*.steenrod_op(i=0, row_symmetry=None, k=3)],
         (0, -2): [*.steenrod_op(i=1, row_symmetry=None, k=3)]}

        sage: v = vandermonde(Diagram([(0,0),(1,0),(3,0)]))
        sage: v
        -x00^3*x01 + x00*x01^3 + x00^3*x02 - x01^3*x02 - x00*x02^3 + x01*x02^3
        sage: gen = {v.multidegree() : [v]}
        sage: op = merge(steenrod_operators(1,1), steenrod_operators(1,2))
        sage: Subspace(gen, op).basis()
        {(3,): (-x00^2*x01 + x00*x01^2 + x00^2*x02 - x01^2*x02 - x00*x02^2 + x01*x02^2,),
         (4,): (-x00^3*x01 + x00*x01^3 + x00^3*x02 - x01^3*x02 - x00*x02^3 + x01*x02^3,)}

    """
    if degree < 1:
        degree = 1
    D = cartesian_product([ZZ for i in range(r)])
    op = {}
    for i in range(r):
        op[D((-degree if j == i else 0 for j in range(r)))] = [
            attrcall("steenrod_op",
                     i=i,
                     k=degree + 1,
                     row_symmetry=row_symmetry)
        ]
    return op
Example #23
0
    def __init__(self, predicate, property, code=None, section=None):
        """

        EXAMPLES::

        """
        active_property_displayers.append(self)
        self._property = property
        if isinstance(predicate, Category):
            predicate = predicate.__contains__
        elif isinstance(predicate, type):
            predicate = predicate.__instancecheck__
        self._predicate = predicate
        if code is not None:
            if isinstance(code, str):
                self.result = attrcall(code)
            else:
                self.result=code
        else:
            self._method = property.lower().replace(" ", "_")
Example #24
0
    def elements(self):
        r"""
        Returns the elements of ``self``

        Those are constructed as the elements below the maximal
        elements of ``self`` in Bruhat order.

        OUTPUT: a :class:`TransitiveIdeal` object

        EXAMPLES::

            sage: PF = WeylGroup(['A',3]).pieri_factors()
            sage: [w.reduced_word() for w in PF.elements()]
            [[3, 2, 1], [2, 1], [1], [], [3, 1], [3], [3, 2], [2]]

        ..seealso:: :meth:`maximal_elements`

        TODO: possibly remove this method and instead have this class
        inherit from :class:`TransitiveIdeal`.
        """
        return TransitiveIdeal(attrcall('bruhat_lower_covers'), self.maximal_elements())
Example #25
0
def partial_derivatives(P):
    """
    Return the partial derivative functions in all the variables of `P` allowed
    for derivation (ie not in the inert variables).
    
    INPUT:
    - `P` -- a diagonal polynomial ring
    
    EXAMPLES::
        sage: P = DiagonalPolynomialRing(QQ, 3, 1)
        sage: partial_derivatives(P)
        {(-1,): [*.derivative(x00), *.derivative(x01), *.derivative(x02)]}
        sage: P = DiagonalPolynomialRing(QQ, 3, 2)
        sage: partial_derivatives(P)
        {(-1, 0): [*.derivative(x00), *.derivative(x01), *.derivative(x02)],
         (0, -1): [*.derivative(x10), *.derivative(x11), *.derivative(x12)]}
        sage: P = DiagonalPolynomialRing(QQ, 3, 1, inert=1)
        sage: partial_derivatives(P)
        {(-1,): [*.derivative(x00), *.derivative(x01), *.derivative(x02)]}

        sage: v = vandermonde(Partition([2,1]))
        sage: gen = {v.multidegree() : [v]}
        sage: op = partial_derivatives(v.parent())
        sage: Subspace(gen, op).basis()
        {(0,): (theta01 - theta02, theta00 - theta02),
         (1,): (x01*theta00 - x02*theta00 - x00*theta01 + x02*theta01 + x00*theta02 - x01*theta02,)}

    """
    n = P.ncols()
    r = P.nrows()
    D = P.grading_set()
    X = P.multivar_pol_ring_variables()
    op = {}
    for i in range(r):
        op[D((-1 if j == i else 0 for j in range(r)))] = [
            attrcall("derivative", X[i, k]) for k in range(n)
        ]
    return op
Example #26
0
    def cartesian_projection(self, i):
        """
        Return the natural projection onto the `i`-th cartesian
        factor of ``self`` as per
        :meth:`Sets.CartesianProducts.ParentMethods.cartesian_projection()
        <sage.categories.sets_cat.Sets.CartesianProducts.ParentMethods.cartesian_projection>`.

        INPUT:

        - ``i`` -- the index of a cartesian factor of ``self``

        EXAMPLES::

            sage: C = Sets().CartesianProducts().example(); C
            The cartesian product of (Set of prime numbers (basic implementation), An example of an infinite enumerated set: the non negative integers, An example of a finite enumerated set: {1,2,3})
            sage: x = C.an_element(); x
            (47, 42, 1)
            sage: pi = C.cartesian_projection(1)
            sage: pi(x)
            42
        """
        assert i in self._sets_keys()
        return attrcall("cartesian_projection", i)
    def summand_projection(self, i):
        """
        Returns the natural projection onto the `i`-th summand of self
        as per
        :meth:`Sets.CartesianProducts.ParentMethods.summand_projection()
        <sage.categories.sets_cat.Sets.CartesianProducts.ParentMethods.summand_projection>`.

        INPUTS:

         - ``i`` -- the index of a summand of self

        EXAMPLES::

            sage: C = Sets().CartesianProducts().example(); C
            The cartesian product of (Set of prime numbers (basic implementation), An example of an infinite enumerated set: the non negative integers, An example of a finite enumerated set: {1,2,3})
            sage: x = C.an_element(); x
            (47, 42, 1)
            sage: pi = C.summand_projection(1)
            sage: pi(x)
            42
        """
        assert i in self._sets_keys()
        return attrcall("summand_projection", i)
Example #28
0
        def order_ideals_lattice(self, as_ideals=True):
            r"""
            Return the lattice of order ideals of a poset ``self``,
            ordered by inclusion.

            The lattice of order ideals of a poset `P` is usually
            denoted by `J(P)`. Its underlying set is the set of order
            ideals of `P`, and its partial order is given by
            inclusion.

            The order ideals of `P` are in a canonical bijection
            with the antichains of `P`. The bijection maps every
            order ideal to the antichain formed by its maximal
            elements. By setting the ``as_ideals`` keyword variable to
            ``False``, one can make this method apply this bijection
            before returning the lattice.

            INPUT:

            - ``as_ideals`` -- Boolean, if ``True`` (default) returns
              a poset on the set of order ideals, otherwise on the set
              of antichains

            EXAMPLES::

                sage: P = Posets.PentagonPoset(facade = True)
                sage: P.cover_relations()
                [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]]
                sage: J = P.order_ideals_lattice(); J
                Finite lattice containing 8 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 2, 3}, {0, 1, 2, 3}, {0, 1, 2, 3, 4}]

            As a lattice on antichains::

                sage: J2 = P.order_ideals_lattice(False); J2
                Finite lattice containing 8 elements
                sage: list(J2)
                [(0,), (1, 2), (1, 3), (1,), (2,), (3,), (4,), ()]

            TESTS::

                sage: J = Posets.DiamondPoset(4, facade = True).order_ideals_lattice(); J
                Finite lattice containing 6 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}]
                sage: J.cover_relations()
                [[{}, {0}], [{0}, {0, 2}], [{0}, {0, 1}], [{0, 2}, {0, 1, 2}], [{0, 1}, {0, 1, 2}], [{0, 1, 2}, {0, 1, 2, 3}]]

            .. NOTE:: we use facade posets in the examples above just
               to ensure a nicer ordering in the output.
            """
            from sage.combinat.posets.lattices import LatticePoset
            if as_ideals:
                from sage.misc.misc import attrcall
                from sage.sets.set import Set
                ideals = [
                    Set(self.order_ideal(antichain))
                    for antichain in self.antichains()
                ]
                return LatticePoset((ideals, attrcall("issubset")))
            else:
                from sage.misc.cachefunc import cached_function
                antichains = [tuple(a) for a in self.antichains()]

                @cached_function
                def is_above(a, xb):
                    return any(self.is_lequal(xa, xb) for xa in a)

                def cmp(a, b):
                    return all(is_above(a, xb) for xb in b)

                return LatticePoset((antichains, cmp))
Example #29
0
        EXAMPLES::

            sage: from mygap import Structure, GAPObject, GAPMorphism
            sage: s = Structure(GAPObject, Objects())
            sage: s.add_class(GAPMorphism)
            sage: s.category
            Category of objects
            sage: s.cls
            <class 'mygap.GAPMorphism'>
        """
        assert issubclass(cls, self.cls)
        self.cls = cls


gap_category_to_structure = {
    "IsIterator": attrcall("add_class", GAPIterator),
    # Cheating a bit: this should be IsMapping, which further requires IsTotal and IsSingleValued
    "IsGeneralMapping": attrcall("add_class", GAPMorphism),
}

true_properties_to_structure = {
    #"IsGroupAsSemigroup": add_axiom("Inverse"), # Useful?
}

false_properties_to_structure = {}


def fill_allignment_database(cls):
    """
    Fill the database mapping gap categories / properties to their
    corresponding (super) Sage categories from the semantic
Example #30
0
        def order_ideals_lattice(self, as_ideals=True):
            r"""
            Return the lattice of order ideals of a poset ``self``,
            ordered by inclusion.

            The lattice of order ideals of a poset `P` is usually
            denoted by `J(P)`. Its underlying set is the set of order
            ideals of `P`, and its partial order is given by
            inclusion.

            The order ideals of `P` are in a canonical bijection
            with the antichains of `P`. The bijection maps every
            order ideal to the antichain formed by its maximal
            elements. By setting the ``as_ideals`` keyword variable to
            ``False``, one can make this method apply this bijection
            before returning the lattice.

            INPUT:

            - ``as_ideals`` -- Boolean, if ``True`` (default) returns
              a poset on the set of order ideals, otherwise on the set
              of antichains

            EXAMPLES::

                sage: P = Posets.PentagonPoset(facade = True)
                sage: P.cover_relations()
                [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]]
                sage: J = P.order_ideals_lattice(); J
                Finite lattice containing 8 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 2, 3}, {0, 1, 2, 3}, {0, 1, 2, 3, 4}]

            As a lattice on antichains::

                sage: J2 = P.order_ideals_lattice(False); J2
                Finite lattice containing 8 elements
                sage: list(J2)
                [(0,), (1, 2), (1, 3), (1,), (2,), (3,), (4,), ()]

            TESTS::

                sage: J = Posets.DiamondPoset(4, facade = True).order_ideals_lattice(); J
                Finite lattice containing 6 elements
                sage: list(J)
                [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}]
                sage: J.cover_relations()
                [[{}, {0}], [{0}, {0, 2}], [{0}, {0, 1}], [{0, 2}, {0, 1, 2}], [{0, 1}, {0, 1, 2}], [{0, 1, 2}, {0, 1, 2, 3}]]

            .. NOTE:: we use facade posets in the examples above just
               to ensure a nicer ordering in the output.
            """
            from sage.combinat.posets.lattices import LatticePoset
            if as_ideals:
                from sage.misc.misc import attrcall
                from sage.sets.set import Set
                ideals = [Set( self.order_ideal(antichain) ) for antichain in self.antichains()]
                return LatticePoset((ideals,attrcall("issubset")))
            else:
                from sage.misc.cachefunc import cached_function
                antichains = [tuple(a) for a in self.antichains()]
                @cached_function
                def is_above(a,xb):
                    return any(self.is_lequal(xa,xb) for xa in a)
                def cmp(a,b):
                    return all(is_above(a,xb) for xb in b)
                return LatticePoset((antichains,cmp))
Example #31
0
def test_finite_poset(P):
    """
    Test several functions on a given finite poset.

    The function contains tests of different kinds, for example

    - Numerical properties jump number, dimension etc. can't be a bigger
      in a subposet with one element less.
    - "Dual tests", for example the dual of meet-semilattice must be a join-semilattice.
    - Random tries: for example if the dimension of a poset is `k`, then it can't be the
      intersection of `k-1` random linear extensions.

    EXAMPLES::

        sage: from sage.tests.finite_poset import test_finite_poset
        sage: P = posets.RandomPoset(10, 0.15)
        sage: test_finite_poset(P) is None  # Long time
        True
    """
    from sage.combinat.posets.posets import Poset
    from sage.combinat.subset import Subsets
    from sage.misc.prandom import shuffle

    from sage.misc.misc import attrcall

    e = P.random_element()
    P_one_less = P.subposet([x for x in P if x != e])

    # Cardinality
    if len(P) != P.cardinality():
        raise ValueError("error 1 in cardinality")
    if P.cardinality() - 1 != P_one_less.cardinality():
        raise ValueError("error 5 in cardinality")

    # Height
    h1 = P.height()
    h2, chain = P.height(certificate=True)
    if h1 != h2:
        raise ValueError("error 1 in height")
    if h1 != len(chain):
        raise ValueError("error 2 in height")
    if not P.is_chain_of_poset(chain):
        raise ValueError("error 3 in height")
    if len(P.random_maximal_chain()) > h1:
        raise ValueError("error 4 in height")
    if h1 - P_one_less.height() not in [0, 1]:
        raise ValueError("error 5 in height")

    # Width
    w1 = P.width()
    w2, antichain = P.width(certificate=True)
    if w1 != w2:
        raise ValueError("error 1 in width")
    if w1 != len(antichain):
        raise ValueError("error 2 in width")
    if not P.is_antichain_of_poset(antichain):
        raise ValueError("error 3 in width")
    if len(P.random_maximal_antichain()) > w1:
        raise ValueError("error 4 in width")
    if w1 - P_one_less.width() not in [0, 1]:
        raise ValueError("error 5 in width")

    # Dimension
    dim1 = P.dimension()
    dim2, linexts = P.dimension(certificate=True)
    if dim1 != dim2:
        raise ValueError("error 1 in dimension")
    if dim1 != len(linexts):
        raise ValueError("error 2 in dimension")
    P_ = Poset((P.list(), lambda a, b: all(
        linext.index(a) < linext.index(b) for linext in linexts)))
    if P_ != Poset(P.hasse_diagram()):
        raise ValueError("error 3 in dimension")
    x = [P.random_linear_extension() for _ in range(dim1 - 1)]
    P_ = Poset(
        (P.list(),
         lambda a, b: all(linext.index(a) < linext.index(b) for linext in x)))
    if P_ == Poset(P.hasse_diagram()):
        raise ValueError("error 4 in dimension")
    if dim1 - P_one_less.dimension() < 0:
        raise ValueError("error 5 in dimension")

    # Jump number
    j1 = P.jump_number()
    j2, linext = P.jump_number(certificate=True)
    if j1 != j2:
        raise ValueError("error 1 in jump number")
    if P.linear_extension(linext).jump_count() != j1:
        raise ValueError("error 2 in jump number")
    if not P.is_linear_extension(linext):
        raise ValueError("error 3 in jump number")
    if P.linear_extension(P.random_linear_extension()).jump_count() < j1:
        raise ValueError("error 4 in jump number")
    if j1 - P_one_less.jump_number() not in [0, 1]:
        raise ValueError("error 5 in jump number")

    P_dual = P.dual()
    selfdual_properties = [
        'chain', 'bounded', 'connected', 'graded', 'ranked', 'series_parallel',
        'slender', 'lattice'
    ]
    for prop in selfdual_properties:
        f = attrcall('is_' + prop)
        if f(P) != f(P_dual):
            raise ValueError("error in self-dual property %s" % prop)
    if P.is_graded():
        if P.is_bounded():
            if P.is_eulerian() != P_dual.is_eulerian():
                raise ValueError("error in self-dual property eulerian")
            if P.is_eulerian():
                P_ = P.star_product(P)
                if not P_.is_eulerian():
                    raise ("error in star product / eulerian")
        chain1 = P.random_maximal_chain()
        if len(chain1) != h1:
            raise ValueError("error in is_graded")
        if not P.is_ranked():
            raise ValueError("error in is_ranked / is_graded")

    if P.is_meet_semilattice() != P_dual.is_join_semilattice():
        raise ValueError("error in meet/join semilattice")

    if set(P.minimal_elements()) != set(P_dual.maximal_elements()):
        raise ValueError("error in min/max elements")
    if P.top() != P_dual.bottom():
        raise ValueError("error in top/bottom element")

    parts = P.connected_components()
    P_ = Poset()
    for part in parts:
        P_ = P_.disjoint_union(part)
    if not P.is_isomorphic(P_):
        raise ValueError("error in connected components / disjoint union")
    parts = P.ordinal_summands()
    P_ = Poset()
    for part in parts:
        P_ = P_.ordinal_sum(part)
    if not P.is_isomorphic(P_):
        raise ValueError("error in ordinal summands / ordinal sum")

    P_ = P.with_bounds().without_bounds()
    if not P.is_isomorphic(P_):
        raise ValueError("error in with bounds / without bounds")

    P_ = P.completion_by_cuts().irreducibles_poset()
    if not P.has_isomorphic_subposet(P_):
        raise ValueError("error in completion by cuts / irreducibles poset")

    P_ = P.subposet(Subsets(P).random_element())
    if not P_.is_induced_subposet(P):
        raise ValueError("error in subposet / is induced subposet")

    if not P.is_linear_extension(P.random_linear_extension()):
        raise ValueError("error in is linear extension")

    x = list(P)
    shuffle(x)
    if not P.is_linear_extension(P.sorted(x)):
        raise ValueError("error in sorted")

    dil = P.dilworth_decomposition()
    chain = dil[randint(0, len(dil) - 1)]
    if not P.is_chain_of_poset(chain):
        raise ValueError("error in Dilworth decomposition")
    lev = P.level_sets()
    level = lev[randint(0, len(lev) - 1)]
    if not P.is_antichain_of_poset(level):
        raise ValueError("error in level sets")

    # certificate=True must return a pair
    bool_with_cert = [
        'eulerian', 'greedy', 'join_semilattice', 'jump_critical',
        'meet_semilattice', 'slender'
    ]
    for p in bool_with_cert:
        try:  # some properties are not always defined for all posets
            res1 = attrcall('is_' + p)(P)
        except ValueError:
            continue
        res2 = attrcall('is_' + p, certificate=True)(P)
        if type(res2) != type((1, 2)) or len(res2) != 2:
            raise ValueError(
                "certificate-option does not return a pair in %s" % p)
        if res1 != res2[0]:
            raise ValueError("certificate-option changes result in %s" % p)
Example #32
0
def test_finite_lattice(L):
    """
    Test several functions on a given finite lattice.

    The function contains tests of different kinds:

    - Implications of Boolean properties. Examples: a distributive lattice is modular,
      a dismantlable and distributive lattice is planar, a simple lattice can not be
      constructible by Day's doublings.
    - Dual and self-dual properties. Examples: Dual of a modular lattice is modular,
      dual of an atomic lattice is co-atomic.
    - Certificate tests. Example: certificate for a non-complemented lattice must be
      an element without a complement.
    - Verification of some property by known property or by a random test.
      Examples: A lattice is distributive iff join-primes are exactly
      join-irreducibles and an interval of a relatively complemented
      lattice is complemented.
    - Set inclusions. Example: Every co-atom must be meet-irreducible.
    - And several other tests. Example: The skeleton of a pseudocomplemented
      lattice must be Boolean.

    EXAMPLES::

        sage: from sage.tests.finite_poset import test_finite_lattice
        sage: L = posets.RandomLattice(10, 0.98)
        sage: test_finite_lattice(L) is None  # Long time
        True
    """
    from sage.combinat.posets.lattices import LatticePoset

    from sage.sets.set import Set
    from sage.combinat.subset import Subsets

    from sage.misc.prandom import randint
    from sage.misc.flatten import flatten
    from sage.misc.misc import attrcall

    from sage.misc.sageinspect import sage_getargspec

    if L.cardinality() < 4:
        # Special cases should be tested in specific TESTS-sections.
        return None

    all_props = set(list(implications) + flatten(implications.values()))
    P = {x: test_attrcall('is_' + x, L) for x in all_props}

    ### Relations between boolean-valued properties ###

    # Direct one-property implications
    for prop1 in implications:
        if P[prop1]:
            for prop2 in implications[prop1]:
                if not P[prop2]:
                    raise ValueError("error: %s should implicate %s" %
                                     (prop1, prop2))

    # Impossible combinations
    for p1, p2 in mutually_exclusive:
        if P[p1] and P[p2]:
            raise ValueError(
                "error: %s and %s should be impossible combination" % (p1, p2))

    # Two-property implications
    for p1, p2, p3 in two_to_one:
        if P[p1] and P[p2] and not P[p3]:
            raise ValueError("error: %s and %s, so should be %s" %
                             (p1, p2, p3))

    Ldual = L.dual()
    # Selfdual properties
    for p in selfdual_properties:
        if P[p] != test_attrcall('is_' + p, Ldual):
            raise ValueError("selfdual property %s error" % p)
    # Dual properties and elements
    for p1, p2 in dual_properties:
        if P[p1] != test_attrcall('is_' + p2, Ldual):
            raise ValueError("dual properties error %s" % p1)
    for e1, e2 in dual_elements:
        if set(attrcall(e1)(L)) != set(attrcall(e2)(Ldual)):
            raise ValueError("dual elements error %s" % e1)

    ### Certificates ###

    # Return value must be a pair with correct result as first element.
    for p_ in all_props:
        # Dirty fix first
        if p_[:9] == 'doubling_' or p_[:5] == 'uniq_': continue
        p = "is_" + p_
        if 'certificate' in sage_getargspec(getattr(L, p)).args:
            res = attrcall(p, certificate=True)(L)
            if type(res) != type((1, 2)) or len(res) != 2:
                raise ValueError(
                    "certificate-option does not return a pair in %s" % p)
            if P[p_] != res[0]:
                raise ValueError("certificate-option changes result in %s" % p)

    # Test for "yes"-certificates
    if P['supersolvable']:
        a = L.is_supersolvable(certificate=True)[1]
        S = Subsets(L).random_element()
        if L.is_chain_of_poset(S):
            if not L.sublattice(a + list(S)).is_distributive():
                raise ValueError("certificate error in is_supersolvable")
    if P['dismantlable']:
        elms = L.is_dismantlable(certificate=True)[1]
        if len(elms) != L.cardinality():
            raise ValueError("certificate error 1 in is_dismantlable")
        elms = elms[:randint(0, len(elms) - 1)]
        L_ = L.sublattice([x for x in L if x not in elms])
        if L_.cardinality() != L.cardinality() - len(elms):
            raise ValueError("certificate error 2 in is_dismantlable")
    if P['vertically_decomposable']:
        c = L.is_vertically_decomposable(certificate=True)[1]
        if c == L.bottom() or c == L.top():
            raise ValueError(
                "certificate error 1 in is_vertically_decomposable")
        e = L.random_element()
        if L.compare_elements(c, e) is None:
            raise ValueError(
                "certificate error 2 in is_vertically_decomposable")

    # Test for "no"-certificates
    if not P['atomic']:
        a = L.is_atomic(certificate=True)[1]
        if a in L.atoms() or a not in L.join_irreducibles():
            raise ValueError("certificate error in is_atomic")
    if not P['coatomic']:
        a = L.is_coatomic(certificate=True)[1]
        if a in L.coatoms() or a not in L.meet_irreducibles():
            raise ValueError("certificate error in is_coatomic")

    if not P['complemented']:
        a = L.is_complemented(certificate=True)[1]
        if L.complements(a) != []:
            raise ValueError("compl. error 1")
    if not P['sectionally_complemented']:
        a, b = L.is_sectionally_complemented(certificate=True)[1]
        L_ = L.sublattice(L.interval(L.bottom(), a))
        if L_.is_complemented():
            raise ValueError("sec. compl. error 1")
        if len(L_.complements(b)) > 0:
            raise ValueError("sec. compl. error 2")
    if not P['cosectionally_complemented']:
        a, b = L.is_cosectionally_complemented(certificate=True)[1]
        L_ = L.sublattice(L.interval(a, L.top()))
        if L_.is_complemented():
            raise ValueError("cosec. compl. error 1")
        if len(L_.complements(b)) > 0:
            raise ValueError("cosec. compl. error 2")
    if not P['relatively_complemented']:
        a, b, c = L.is_relatively_complemented(certificate=True)[1]
        I = L.interval(a, c)
        if len(I) != 3 or b not in I:
            raise ValueError("rel. compl. error 1")

    if not P['upper_semimodular']:
        a, b = L.is_upper_semimodular(certificate=True)[1]
        if not set(L.lower_covers(a)).intersection(set(
                L.lower_covers(b))) or set(L.upper_covers(a)).intersection(
                    set(L.upper_covers(b))):
            raise ValueError("certificate error in is_upper_semimodular")
    if not P['lower_semimodular']:
        a, b = L.is_lower_semimodular(certificate=True)[1]
        if set(L.lower_covers(a)).intersection(set(
                L.lower_covers(b))) or not set(L.upper_covers(a)).intersection(
                    set(L.upper_covers(b))):
            raise ValueError("certificate error in is_lower_semimodular")

    if not P['distributive']:
        x, y, z = L.is_distributive(certificate=True)[1]
        if L.meet(x, L.join(y, z)) == L.join(L.meet(x, y), L.meet(x, z)):
            raise ValueError("certificate error in is_distributive")
    if not P['modular']:
        x, a, b = L.is_modular(certificate=True)[1]
        if not L.is_less_than(x, b) or L.join(x, L.meet(a, b)) == L.meet(
                L.join(x, a), b):
            raise ValueError("certificate error in is_modular")

    if not P['pseudocomplemented']:
        a = L.is_pseudocomplemented(certificate=True)[1]
        L_ = L.subposet([e for e in L if L.meet(e, a) == L.bottom()])
        if L_.has_top():
            raise ValueError("certificate error in is_pseudocomplemented")
    if not P['join_pseudocomplemented']:
        a = L.is_join_pseudocomplemented(certificate=True)[1]
        L_ = L.subposet([e for e in L if L.join(e, a) == L.top()])
        if L_.has_bottom():
            raise ValueError("certificate error in is_join_pseudocomplemented")

    if not P['join_semidistributive']:
        e, x, y = L.is_join_semidistributive(certificate=True)[1]
        if L.join(e, x) != L.join(e, y) or L.join(e, x) == L.join(
                e, L.meet(x, y)):
            raise ValueError("certificate error in is_join_semidistributive")
    if not P['meet_semidistributive']:
        e, x, y = L.is_meet_semidistributive(certificate=True)[1]
        if L.meet(e, x) != L.meet(e, y) or L.meet(e, x) == L.meet(
                e, L.join(x, y)):
            raise ValueError("certificate error in is_meet_semidistributive")

    if not P['simple']:
        c = L.is_simple(certificate=True)[1]
        if len(L.congruence([c[randint(0, len(c) - 1)]])) == 1:
            raise ValueError("certificate error in is_simple")
    if not P['isoform']:
        c = L.is_isoform(certificate=True)[1]
        if len(c) == 1:
            raise ValueError("certificate error in is_isoform")
        if all(
                L.subposet(c[i]).is_isomorphic(L.subposet(c[i + 1]))
                for i in range(len(c) - 1)):
            raise ValueError("certificate error in is_isoform")
    if not P['uniform']:
        c = L.is_uniform(certificate=True)[1]
        if len(c) == 1:
            raise ValueError("certificate error in is_uniform")
        if all(len(c[i]) == len(c[i + 1]) for i in range(len(c) - 1)):
            raise ValueError("certificate error in is_uniform")
    if not P['regular']:
        c = L.is_regular(certificate=True)[1]
        if len(c[0]) == 1:
            raise ValueError("certificate error 1 in is_regular")
        if Set(c[1]) not in c[0]:
            raise ValueError("certificate error 2 in is_regular")
        if L.congruence([c[1]]) == c[0]:
            raise ValueError("certificate error 3 in is_regular")

    if not P['subdirectly_reducible']:
        x, y = L.is_subdirectly_reducible(certificate=True)[1]
        a = L.random_element()
        b = L.random_element()
        c = L.congruence([[a, b]])
        if len(c) != L.cardinality():
            for c_ in c:
                if x in c_:
                    if y not in c_:
                        raise ValueError(
                            "certificate error 1 in is_subdirectly_reducible")
                    break
            else:
                raise ValueError(
                    "certificate error 2 in is_subdirectly_reducible")

    if not P['join_distributive']:
        a = L.is_join_distributive(certificate=True)[1]
        L_ = L.sublattice(L.interval(a, L.join(L.upper_covers(a))))
        if L_.is_distributive():
            raise ValueError("certificate error in is_join_distributive")
    if not P['meet_distributive']:
        a = L.is_meet_distributive(certificate=True)[1]
        L_ = L.sublattice(L.interval(L.meet(L.lower_covers(a)), a))
        if L_.is_distributive():
            raise ValueError("certificate error in is_meet_distributive")

    ### Other ###

    # Other ways to recognize some boolean property
    if P['distributive'] != (set(L.join_primes()) == set(
            L.join_irreducibles())):
        raise ValueError(
            "every join-irreducible of a distributive lattice should be join-prime"
        )
    if P['distributive'] != (set(L.meet_primes()) == set(
            L.meet_irreducibles())):
        raise ValueError(
            "every meet-irreducible of a distributive lattice should be meet-prime"
        )
    if P['join_semidistributive'] != all(
            L.canonical_joinands(e) is not None for e in L):
        raise ValueError(
            "every element of join-semidistributive lattice should have canonical joinands"
        )
    if P['meet_semidistributive'] != all(
            L.canonical_meetands(e) is not None for e in L):
        raise ValueError(
            "every element of meet-semidistributive lattice should have canonical meetands"
        )

    # Random verification of a Boolean property
    if P['relatively_complemented']:
        a = L.random_element()
        b = L.random_element()
        if not L.sublattice(L.interval(a, b)).is_complemented():
            raise ValueError("rel. compl. error 3")
    if P['sectionally_complemented']:
        a = L.random_element()
        if not L.sublattice(L.interval(L.bottom(), a)).is_complemented():
            raise ValueError("sec. compl. error 3")
    if P['cosectionally_complemented']:
        a = L.random_element()
        if not L.sublattice(L.interval(a, L.top())).is_complemented():
            raise ValueError("cosec. compl. error 2")

    # Element set inclusions
    for s1, s2 in set_inclusions:
        if not set(attrcall(s1)(L)).issubset(set(attrcall(s2)(L))):
            raise ValueError("%s should be a subset of %s" % (s1, s2))

    # Sublattice-closed properties
    L_ = L.sublattice(Subsets(L).random_element())
    for p in sublattice_closed:
        if P[p] and not test_attrcall('is_' + p, L_):
            raise ValueError("property %s should apply to sublattices" % p)

    # Some sublattices
    L_ = L.center()  # Center is a Boolean lattice
    if not L_.is_atomic() or not L_.is_distributive():
        raise ValueError("error in center")
    if P['pseudocomplemented']:
        L_ = L.skeleton()  # Skeleton is a Boolean lattice
        if not L_.is_atomic() or not L_.is_distributive():
            raise ValueError("error in skeleton")
    L_ = L.frattini_sublattice()
    S = Subsets(L).random_element()
    if L.sublattice(S) == L and L.sublattice([e
                                              for e in S if e not in L_]) != L:
        raise ValueError("error in Frattini sublattice")
    L_ = L.maximal_sublattices()
    L_ = L_[randint(0, len(L_) - 1)]
    e = L.random_element()
    if e not in L_ and L.sublattice(list(L_) + [e]) != L:
        raise ValueError("error in maximal_sublattices")

    # Reverse functions: vertical composition and decomposition
    L_ = reduce(lambda a, b: a.vertical_composition(b),
                L.vertical_decomposition(), LatticePoset())
    if not L.is_isomorphic(L_):
        raise ValueError("error in vertical [de]composition")

    # Meet and join
    a = L.random_element()
    b = L.random_element()
    m = L.meet(a, b)
    j = L.join(a, b)
    m_ = L.subposet([
        e for e in L.principal_lower_set(a) if e in L.principal_lower_set(b)
    ]).top()
    j_ = L.subposet([
        e for e in L.principal_upper_set(a) if e in L.principal_upper_set(b)
    ]).bottom()
    if m != m_ or m != Ldual.join(a, b):
        raise ValueError("error in meet")
    if j != j_ or j != Ldual.meet(a, b):
        raise ValueError("error in join")

    # Misc misc
    e = L.neutral_elements()
    e = e[randint(0, len(e) - 1)]
    a = L.random_element()
    b = L.random_element()
    if not L.sublattice([e, a, b]).is_distributive():
        raise ValueError("error in neutral_elements")
Example #33
0
    """
    if hasattr(type, "specialize"):
        return type.specialize(value)
    else:
        return type

def GenericMeta_specialize(self, value):
    return self.copy_with(tuple(specialize(a, value) for a in self.__args__))
_GenericAlias.specialize = GenericMeta_specialize

Family = _GenericAlias(sage.sets.family.TrivialFamily, typing.T)
class _Facade:
    pass
Facade = _GenericAlias(_Facade, typing.T)

Sage         = attrcall("sage")

# Class for dependent types constructed from a callable value -> type
# 
class DependentType:#(typing._TypingBase): # Singleton
    #__metaclass__ = typing.TypingMeta
    __slots__ = ("name", "specialize")
    # Should be callable?
    def __init__(self, specialize, name):
        self.name = name
        self.specialize = specialize
    def __instancecheck__(self, object):
        raise TypeError("Unspecialized {} cannot be used with isinstance()".format(self))
    def __repr__(self):
        return self.name
    def __call__(self, o):
Example #34
0
def test_finite_lattice(L):
    """
    Test several functions on a given finite lattice.

    The function contains tests of different kinds:

    - Implications of Boolean properties. Examples: a distributive lattice is modular,
      a dismantlable and distributive lattice is planar, a simple lattice can not be
      constructible by Day's doublings.
    - Dual and self-dual properties. Examples: Dual of a modular lattice is modular,
      dual of an atomic lattice is co-atomic.
    - Certificate tests. Example: certificate for a non-complemented lattice must be
      an element without a complement.
    - Verification of some property by known property or by a random test.
      Examples: A lattice is distributive iff join-primes are exactly
      join-irreducibles and an interval of a relatively complemented
      lattice is complemented.
    - Set inclusions. Example: Every co-atom must be meet-irreducible.
    - And several other tests. Example: The skeleton of a pseudocomplemented
      lattice must be Boolean.

    EXAMPLES::

        sage: from sage.tests.finite_poset import test_finite_lattice
        sage: L = posets.RandomLattice(10, 0.98)
        sage: test_finite_lattice(L) is None  # Long time
        True
    """
    from sage.combinat.posets.lattices import LatticePoset

    from sage.sets.set import Set
    from sage.combinat.subset import Subsets

    from sage.misc.prandom import randint
    from sage.misc.flatten import flatten
    from sage.misc.misc import attrcall

    if L.cardinality() < 4:
        # Special cases should be tested in specific TESTS-sections.
        return None

    all_props = set(list(implications) + flatten(implications.values()))
    P = {x: test_attrcall('is_' + x, L) for x in all_props}

    ### Relations between boolean-valued properties ###

    # Direct one-property implications
    for prop1 in implications:
        if P[prop1]:
            for prop2 in implications[prop1]:
                if not P[prop2]:
                    raise ValueError("error: %s should implicate %s" % (prop1, prop2))

    # Impossible combinations
    for p1, p2 in mutually_exclusive:
        if P[p1] and P[p2]:
            raise ValueError("error: %s and %s should be impossible combination" % (p1, p2))

    # Two-property implications
    for p1, p2, p3 in two_to_one:
        if P[p1] and P[p2] and not P[p3]:
            raise ValueError("error: %s and %s, so should be %s" % (p1, p2, p3))

    Ldual = L.dual()
    # Selfdual properties
    for p in selfdual_properties:
        if P[p] != test_attrcall('is_'+p, Ldual):
            raise ValueError("selfdual property %s error" % p)
    # Dual properties and elements
    for p1, p2 in dual_properties:
        if P[p1] != test_attrcall('is_'+p2, Ldual):
            raise ValueError("dual properties error %s" % p1)
    for e1, e2 in dual_elements:
        if set(attrcall(e1)(L)) != set(attrcall(e2)(Ldual)):
            raise ValueError("dual elements error %s" % e1)

    ### Certificates ###

    # Test for "yes"-certificates
    if P['supersolvable']:
        a = L.is_supersolvable(certificate=True)[1]
        S = Subsets(L).random_element()
        if L.is_chain_of_poset(S):
            if not L.sublattice(a+list(S)).is_distributive():
                raise ValueError("certificate error in is_supersolvable")
    if P['dismantlable']:
        elms = L.is_dismantlable(certificate=True)[1]
        if len(elms) != L.cardinality():
            raise ValueError("certificate error 1 in is_dismantlable")
        elms = elms[:randint(0, len(elms)-1)]
        L_ = L.sublattice([x for x in L if x not in elms])
        if L_.cardinality() != L.cardinality() - len(elms):
            raise ValueError("certificate error 2 in is_dismantlable")
    if P['vertically_decomposable']:
        c = L.is_vertically_decomposable(certificate=True)[1]
        if c == L.bottom() or c == L.top():
            raise ValueError("certificate error 1 in is_vertically_decomposable")
        e = L.random_element()
        if L.compare_elements(c, e) is None:
            raise ValueError("certificate error 2 in is_vertically_decomposable")

    # Test for "no"-certificates
    if not P['atomic']:
        a = L.is_atomic(certificate=True)[1]
        if a in L.atoms() or a not in L.join_irreducibles():
            raise ValueError("certificate error in is_atomic")
    if not P['coatomic']:
        a = L.is_coatomic(certificate=True)[1]
        if a in L.coatoms() or a not in L.meet_irreducibles():
            raise ValueError("certificate error in is_coatomic")

    if not P['complemented']:
        a = L.is_complemented(certificate=True)[1]
        if L.complements(a) != []:
            raise ValueError("compl. error 1")
    if not P['sectionally_complemented']:
        a, b = L.is_sectionally_complemented(certificate=True)[1]
        L_ = L.sublattice(L.interval(L.bottom(), a))
        if L_.is_complemented():
            raise ValueError("sec. compl. error 1")
        if len(L_.complements(b)) > 0:
            raise ValueError("sec. compl. error 2")
    if not P['cosectionally_complemented']:
        a, b = L.is_cosectionally_complemented(certificate=True)[1]
        L_ = L.sublattice(L.interval(a, L.top()))
        if L_.is_complemented():
            raise ValueError("cosec. compl. error 1")
        if len(L_.complements(b)) > 0:
            raise ValueError("cosec. compl. error 2")
    if not P['relatively_complemented']:
        a, b, c = L.is_relatively_complemented(certificate=True)[1]
        I = L.interval(a, c)
        if len(I) != 3 or b not in I:
            raise ValueError("rel. compl. error 1")

    if not P['upper_semimodular']:
        a, b = L.is_upper_semimodular(certificate=True)[1]
        if not set(L.lower_covers(a)).intersection(set(L.lower_covers(b))) or set(L.upper_covers(a)).intersection(set(L.upper_covers(b))):
            raise ValueError("certificate error in is_upper_semimodular")
    if not P['lower_semimodular']:
        a, b = L.is_lower_semimodular(certificate=True)[1]
        if set(L.lower_covers(a)).intersection(set(L.lower_covers(b))) or not set(L.upper_covers(a)).intersection(set(L.upper_covers(b))):
            raise ValueError("certificate error in is_lower_semimodular")

    if not P['distributive']:
        x, y, z = L.is_distributive(certificate=True)[1]
        if L.meet(x, L.join(y, z)) == L.join(L.meet(x, y), L.meet(x, z)):
            raise ValueError("certificate error in is_distributive")
    if not P['modular']:
        x, a, b = L.is_modular(certificate=True)[1]
        if not L.is_less_than(x, b) or L.join(x, L.meet(a, b)) == L.meet(L.join(x, a), b):
            raise ValueError("certificate error in is_modular")

    if not P['pseudocomplemented']:
        a = L.is_pseudocomplemented(certificate=True)[1]
        L_ = L.subposet([e for e in L if L.meet(e, a) == L.bottom()])
        if L_.has_top():
            raise ValueError("certificate error in is_pseudocomplemented")
    if not P['join_pseudocomplemented']:
        a = L.is_join_pseudocomplemented(certificate=True)[1]
        L_ = L.subposet([e for e in L if L.join(e, a) == L.top()])
        if L_.has_bottom():
            raise ValueError("certificate error in is_join_pseudocomplemented")

    if not P['join_semidistributive']:
        e, x, y = L.is_join_semidistributive(certificate=True)[1]
        if L.join(e, x) != L.join(e, y) or L.join(e, x) == L.join(e, L.meet(x, y)):
            raise ValueError("certificate error in is_join_semidistributive")
    if not P['meet_semidistributive']:
        e, x, y = L.is_meet_semidistributive(certificate=True)[1]
        if L.meet(e, x) != L.meet(e, y) or L.meet(e, x) == L.meet(e, L.join(x, y)):
            raise ValueError("certificate error in is_meet_semidistributive")

    if not P['simple']:
        c = L.is_simple(certificate=True)[1]
        if len(L.congruence([c[randint(0, len(c)-1)]])) == 1:
            raise ValueError("certificate error in is_simple")
    if not P['isoform']:
        c = L.is_isoform(certificate=True)[1]
        if len(c) == 1:
            raise ValueError("certificate error in is_isoform")
        if all(L.subposet(c[i]).is_isomorphic(L.subposet(c[i+1])) for i in range(len(c)-1)):
            raise ValueError("certificate error in is_isoform")
    if not P['uniform']:
        c = L.is_uniform(certificate=True)[1]
        if len(c) == 1:
            raise ValueError("certificate error in is_uniform")
        if all(len(c[i]) == len(c[i+1]) for i in range(len(c)-1)):
            raise ValueError("certificate error in is_uniform")
    if not P['regular']:
        c = L.is_regular(certificate=True)[1]
        if len(c[0]) == 1:
            raise ValueError("certificate error 1 in is_regular")
        if Set(c[1]) not in c[0]:
            raise ValueError("certificate error 2 in is_regular")
        if L.congruence([c[1]]) == c[0]:
            raise ValueError("certificate error 3 in is_regular")

    if not P['subdirectly_reducible']:
        x, y = L.is_subdirectly_reducible(certificate=True)[1]
        a = L.random_element(); b = L.random_element()
        c = L.congruence([[a, b]])
        if len(c) != L.cardinality():
            for c_ in c:
                if x in c_:
                    if y not in c_:
                        raise ValueError("certificate error 1 in is_subdirectly_reducible")
                    break
            else:
                raise ValueError("certificate error 2 in is_subdirectly_reducible")

    if not P['join_distributive']:
        a = L.is_join_distributive(certificate=True)[1]
        L_ = L.sublattice(L.interval(a, L.join(L.upper_covers(a))))
        if L_.is_distributive():
            raise ValueError("certificate error in is_join_distributive")
    if not P['meet_distributive']:
        a = L.is_meet_distributive(certificate=True)[1]
        L_ = L.sublattice(L.interval(L.meet(L.lower_covers(a)), a))
        if L_.is_distributive():
            raise ValueError("certificate error in is_meet_distributive")

    ### Other ###

    # Other ways to recognize some boolean property
    if P['distributive'] != (set(L.join_primes()) == set(L.join_irreducibles())):
        raise ValueError("every join-irreducible of a distributive lattice should be join-prime")
    if P['distributive'] != (set(L.meet_primes()) == set(L.meet_irreducibles())):
        raise ValueError("every meet-irreducible of a distributive lattice should be meet-prime")
    if P['join_semidistributive'] != all(L.canonical_joinands(e) is not None for e in L):
        raise ValueError("every element of join-semidistributive lattice should have canonical joinands")
    if P['meet_semidistributive'] != all(L.canonical_meetands(e) is not None for e in L):
        raise ValueError("every element of meet-semidistributive lattice should have canonical meetands")

    # Random verification of a Boolean property
    if P['relatively_complemented']:
        a = L.random_element()
        b = L.random_element()
        if not L.sublattice(L.interval(a, b)).is_complemented():
            raise ValueError("rel. compl. error 3")
    if P['sectionally_complemented']:
        a = L.random_element()
        if not L.sublattice(L.interval(L.bottom(), a)).is_complemented():
            raise ValueError("sec. compl. error 3")
    if P['cosectionally_complemented']:
        a = L.random_element()
        if not L.sublattice(L.interval(a, L.top())).is_complemented():
            raise ValueError("cosec. compl. error 2")

    # Element set inclusions
    for s1, s2 in set_inclusions:
        if not set(attrcall(s1)(L)).issubset(set(attrcall(s2)(L))):
            raise ValueError("%s should be a subset of %s" % (s1, s2))

    # Sublattice-closed properties
    L_ = L.sublattice(Subsets(L).random_element())
    for p in sublattice_closed:
        if P[p] and not test_attrcall('is_'+p, L_):
            raise ValueError("property %s should apply to sublattices" % p)

    # Some sublattices
    L_ = L.center()  # Center is a Boolean lattice
    if not L_.is_atomic() or not L_.is_distributive():
        raise ValueError("error in center")
    if P['pseudocomplemented']:
        L_ = L.skeleton()  # Skeleton is a Boolean lattice
        if not L_.is_atomic() or not L_.is_distributive():
            raise ValueError("error in skeleton")
    L_ = L.frattini_sublattice()
    S = Subsets(L).random_element()
    if L.sublattice(S) == L and L.sublattice([e for e in S if e not in L_]) != L:
        raise ValueError("error in Frattini sublattice")
    L_ = L.maximal_sublattices()
    L_ = L_[randint(0, len(L_)-1)]
    e = L.random_element()
    if e not in L_ and L.sublattice(list(L_)+[e]) != L:
        raise ValueError("error in maximal_sublattices")

    # Reverse functions: vertical composition and decomposition
    L_ = reduce(lambda a, b: a.vertical_composition(b), L.vertical_decomposition(), LatticePoset())
    if not L.is_isomorphic(L_):
        raise ValueError("error in vertical [de]composition")

    # Meet and join
    a = L.random_element()
    b = L.random_element()
    m = L.meet(a, b)
    j = L.join(a, b)
    m_ = L.subposet([e for e in L.principal_lower_set(a) if e in L.principal_lower_set(b)]).top()
    j_ = L.subposet([e for e in L.principal_upper_set(a) if e in L.principal_upper_set(b)]).bottom()
    if m != m_ or m != Ldual.join(a, b):
        raise ValueError("error in meet")
    if j != j_ or j != Ldual.meet(a, b):
        raise ValueError("error in join")

    # Misc misc
    e = L.neutral_elements()
    e = e[randint(0, len(e)-1)]
    a = L.random_element(); b = L.random_element()
    if not L.sublattice([e, a, b]).is_distributive():
        raise ValueError("error in neutral_elements")
def f(i):
    """
    # TODO NICOLAS add documentation
    """
    return attrcall("polarization", i1=i + 1, i2=i, d=1)
Example #36
0
        def hom_to_module(self, module):
            """
            INPUT:

            - ``module`` -- a vector space affording a representation
                of ``self.semigroup()`` implemented as ``module.action(s, x)``

            Assume that this module is cyclic, with generator `g` (see
            :meth:`module_generator`), and let `S` be the semigroup
            acting on ``self`` (see :meth:`self.semigroup`). For
            short, we write `x . s` the action of `s` on `x`.

            This returns the subspace `M` of all elements `x` of
            ``module`` such that `g \mapsto x` extends to a morphism
            of `S`-modules; equivalently `x` must satisfy the
            following system of linear equations:

            .. math:  g . s = None  \Rightarrow x . s = 0,       \forall s\in S
            .. math:  g . s == g. t \Rightarrow x . s == x . t,  \forall s,t\in S

            In practice, the system of equation can be reduced to one
            equation for each pair `u,i` with `u` in ``self`` and `i`
            index of a semigroup generator of `S`.

            EXAMPLES::

            The cayley graph of the regular left class of the bi-Hecke
            monoid indexed by 13452::

                sage: big = DiGraph([(0, 0, -3), (0, 0, 3), (0, 1, -4), (0, 3, 2),
                ...                (1, 0, 3), (1, 1, -4), (1, 1, 4),
                ...                (2, 1, -4), (2, 2, -3), (2, 2, 3), (2, 3, 2),
                ...                (3, 2, -3), (3, 3, -2), (3, 3, 2)
                ...               ]).transition_module()
                sage: small = DiGraph([(0, 0, -2), (0, 0, 2)]).transition_module()

            """
            from sage.misc.misc import attrcall
            alphabet = self.semigroup().semigroup_generators().keys()
            S = module.semigroup()
            s = S.semigroup_generators()
            assert set(alphabet).issubset(set(s.keys()))

            # Let's see they Cayley graph of ``self`` as an automaton
            G = self.cayley_graph()
            # Now we build, for each vertex `u`, a shortest word `w_u` in the
            # alphabet mapping ``self.module_generator()`` to `u`.
            # Below we write `s_{w_u}` for the element of the semigroup
            # corresponding to `w_u`.
            paths = G.shortest_paths(self.module_generator())
            words = dict( (u, tuple( G.edge_label(path[i],path[i+1])[0]  for i in range(len(path)-1) ))
                          for u,path in paths.iteritems() )
            @cached_function
            def word_action(word, x):
                """
                INPUT:

                 - ``word`` -- a tuple `i_1,\dots,i_k` in the
                   generators of ``S`` representing a path in ``G``
                 - ``x`` -- and element of ``module``

                Writing x.s for the result of the action of `s\in S`
                on `x`, this returns ``x.s_{i_1}.\dots.s_{i_k}``.

                The result is cached over prefixes. This function will
                only be called for `x` in the basis of ``module``.
                """
                if len(word) == 0:
                    return x
                else:
                    return module.action(s[word[-1]], word_action(word[:-1], x))

            def biword_action(word1, word2, x):
                """
                Return the difference of the action of word1 and word2 on `x`
                """
                return word_action(word1,x) - word_action(word2,x)

            # Build the equations, encoded as linear morphisms
            morphisms = []
            alphabet = S.semigroup_generators().keys()
            for u in G.vertices():
                for i in alphabet:
                    v = G.transition(u,i)
                    if v is None:
                        # Add morphism `x -> x . s_{w_u} s_i`
                        morphisms.append( functools.partial(word_action, words[u]+(i,) ) )
                    else:
                        # Add morphism `x ->  x . s_{w_u} s_i - x . s_{w_v}`
                        morphisms.append( functools.partial(biword_action, words[u]+(i,), words[v] ) )
            # Computes the joint kernel of those morphisms.
            return module.annihilator( morphisms, action = attrcall("__call__"), side = "left" )