Exemplo n.º 1
0
    def __init__(self, m, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = ZZ(m)
        self._n = ZZ(n)
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)

        if self._m == 1 or self._m == 2:
            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
            category = FiniteCoxeterGroups().Irreducible()
        else:
            from sage.categories.complex_reflection_groups import ComplexReflectionGroups
            category = ComplexReflectionGroups().Finite().Irreducible(
            ).WellGenerated()
        Parent.__init__(self, category=category)
Exemplo n.º 2
0
    def SymmetricGroupWeakOrderPoset(n, labels="permutations"):
        """
        The poset of permutations with respect to weak order.

        EXAMPLES::

            sage: Posets.SymmetricGroupWeakOrderPoset(4)
            Finite poset containing 24 elements
        """
        if n < 10 and labels == "permutations":
            element_labels = dict([[s, "".join(map(str, s))]
                                   for s in Permutations(n)])
        if n < 10 and labels == "reduced_words":
            element_labels = dict(
                [[s, "".join(map(str, s.reduced_word_lexmin()))]
                 for s in Permutations(n)])

        def weak_covers(s):
            r"""
            Nested function for computing the covers of elements in the
            poset of weak order for the symmetric group.
            """
            return [
                v for v in s.bruhat_succ()
                if s.length() + (s.inverse() * v).length() == v.length()
            ]

        return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]),
                     element_labels)
Exemplo n.º 3
0
    def cross_polytope(self, dim_n):
        """
        Return a cross-polytope in dimension ``dim_n``. These are
        the generalization of the octahedron.

        INPUT:

        - ``dim_n`` -- integer. The dimension of the cross-polytope.

        OUTPUT:

        A Polyhedron object of the ``dim_n``-dimensional cross-polytope,
        with exact coordinates.

        EXAMPLES::

            sage: four_cross = polytopes.cross_polytope(4)
            sage: four_cross.is_simple()
            False
            sage: four_cross.n_vertices()
            8
        """
        verts = Permutations([0 for i in range(dim_n - 1)] + [1]).list()
        verts += Permutations([0 for i in range(dim_n - 1)] + [-1]).list()
        return Polyhedron(vertices=verts)
Exemplo n.º 4
0
    def six_hundred_cell(self):
        """
        Return the standard 600-cell polytope.

        OUTPUT:

        A Polyhedron object of the 4-dimensional 600-cell, a regular
        polytope.  In many ways this is an analogue of the
        icosahedron.  The coordinates of this polytope are rational
        approximations of the true coordinates of the 600-cell, some
        of which involve the (irrational) golden ratio.

        EXAMPLES::

            sage: p600 = polytopes.six_hundred_cell() # not tested - very long time
            sage: len(list(p600.bounded_edges())) # not tested - very long time
            120
        """
        verts = []
        q12 = QQ(1) / 2
        base = [q12, q12, q12, q12]
        for i in range(2):
            for j in range(2):
                for k in range(2):
                    for l in range(2):
                        verts.append([x for x in base])
                        base[3] = base[3] * (-1)
                    base[2] = base[2] * (-1)
                base[1] = base[1] * (-1)
            base[0] = base[0] * (-1)
        verts += Permutations([0, 0, 0, 1]).list()
        verts += Permutations([0, 0, 0, -1]).list()
        g = QQ(1618033) / 1000000  # Golden ratio approximation
        verts = verts + [
            i([q12, g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        verts = verts + [
            i([q12, g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        verts = verts + [
            i([q12, -g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        verts = verts + [
            i([q12, -g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        verts = verts + [
            i([-q12, g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        verts = verts + [
            i([-q12, g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        verts = verts + [
            i([-q12, -g / 2, 1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        verts = verts + [
            i([-q12, -g / 2, -1 / (g * 2), 0]) for i in AlternatingGroup(4)
        ]
        return Polyhedron(vertices=verts)
Exemplo n.º 5
0
    def __iter__(self):
        r"""
        Efficient generation of Baxter permutations.

        OUTPUT:

        An iterator over the Baxter permutations of size ``self._n``.

        EXAMPLES::

            sage: BaxterPermutations(4).list()
            [[4, 3, 2, 1], [3, 4, 2, 1], [3, 2, 4, 1], [3, 2, 1, 4], [2, 4, 3, 1],
             [4, 2, 3, 1], [2, 3, 4, 1], [2, 3, 1, 4], [2, 1, 4, 3], [4, 2, 1, 3],
             [2, 1, 3, 4], [1, 4, 3, 2], [4, 1, 3, 2], [1, 3, 4, 2], [1, 3, 2, 4],
             [4, 3, 1, 2], [3, 4, 1, 2], [3, 1, 2, 4], [1, 2, 4, 3], [1, 4, 2, 3],
             [4, 1, 2, 3], [1, 2, 3, 4]]
            sage: [len(BaxterPermutations(n)) for n in xrange(9)]
            [1, 1, 2, 6, 22, 92, 422, 2074, 10754]

        TESTS::

            sage: all(a in BaxterPermutations(n) for n in xrange(7)
            ....:     for a in BaxterPermutations(n))
            True

        ALGORITHM:

        The algorithm using generating trees described in [BBF08]_ is used.
        The idea is that all Baxter permutations of size `n + 1` can be
        obtained by inserting the letter `n + 1` either just before a left
        to right maximum or just after a right to left maximum of a Baxter
        permutation of size `n`.

        REFERENCES:

        .. [BBF08] N. Bonichon, M. Bousquet-Melou, E. Fusy.
           Baxter permutations and plane bipolar orientations.
           Seminaire Lotharingien de combinatoire 61A, article B61Ah, 2008.
        """
        if self._n == 0:
            yield Permutations(0)([])
        elif self._n == 1:
            yield Permutations(1)([1])
        else:
            for b in BaxterPermutations(self._n - 1):
                # Left to right maxima.
                for i in [self._n - 2 - i for i in b.reverse().saliances()]:
                    yield Permutations(self._n)(b[:i] + [self._n] + b[i:])
                # Right to left maxima.
                for i in b.saliances():
                    yield Permutations(self._n)(b[:i + 1] + [self._n] +
                                                b[i + 1:])
Exemplo n.º 6
0
    def SymmetricGroupBruhatOrderPoset(n):
        """
        The poset of permutations with respect to Bruhat order.

        EXAMPLES::

            sage: Posets.SymmetricGroupBruhatOrderPoset(4)
            Finite poset containing 24 elements
        """
        if n < 10:
            element_labels = dict([[s,"".join(map(str,s))] for s in Permutations(n)])
        return Poset(dict([[s,s.bruhat_succ()]
                for s in Permutations(n)]),element_labels)
Exemplo n.º 7
0
    def __init__(self, R):
        """
        EXAMPLES::

            sage: X = SchubertPolynomialRing(QQ)
            sage: X == loads(dumps(X))
            True
        """
        self._name = "Schubert polynomial ring with X basis"
        self._repr_option_bracket = False
        self._one = Permutations()([1])
        CombinatorialAlgebra.__init__(self, R, cc = Permutations(), category = GradedAlgebrasWithBasis(R))
        self.print_options(prefix='X')
Exemplo n.º 8
0
    def SymmetricGroupWeakOrderPoset(n, labels="permutations", side="right"):
        r"""
        The poset of permutations of `\{ 1, 2, \ldots, n \}` with respect
        to the weak order (also known as the permutohedron order, cf.
        :meth:`~sage.combinat.permutation.Permutation.permutohedron_lequal`).

        The optional variable ``labels`` (default: ``"permutations"``)
        determines the labelling of the elements if `n < 10`. The optional
        variable ``side`` (default: ``"right"``) determines whether the
        right or the left permutohedron order is to be used.

        EXAMPLES::

            sage: Posets.SymmetricGroupWeakOrderPoset(4)
            Finite poset containing 24 elements
        """
        if n < 10 and labels == "permutations":
            element_labels = dict([[s, "".join(map(str, s))]
                                   for s in Permutations(n)])
        if n < 10 and labels == "reduced_words":
            element_labels = dict(
                [[s, "".join(map(str, s.reduced_word_lexmin()))]
                 for s in Permutations(n)])
        if side == "left":

            def weak_covers(s):
                r"""
                Nested function for computing the covers of elements in the
                poset of left weak order for the symmetric group.
                """
                return [
                    v for v in s.bruhat_succ() if s.length() +
                    (s.inverse().right_action_product(v)).length() ==
                    v.length()
                ]
        else:

            def weak_covers(s):
                r"""
                Nested function for computing the covers of elements in the
                poset of right weak order for the symmetric group.
                """
                return [
                    v for v in s.bruhat_succ() if s.length() +
                    (s.inverse().left_action_product(v)).length() ==
                    v.length()
                ]

        return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]),
                     element_labels)
Exemplo n.º 9
0
    def _generate_flags_slow(self):

        sys.stdout.write("Generating flags (SLOW VERSION).\n")
        sys.stdout.flush()
        
        flags = list()

        sys.stdout.write("Generating flags... ")
        
        for t in self.types:
            t_flags = list()
            n = int((self.N-t.N)/2 +t.N) # must be casted as int
            allperms = [PermFlag(x) for x in Permutations(n)]
            S = Subsets(range(n),t.N)

            for p in allperms: # check each permutation 
                for s in S: # and all possible placings of type in it
                    subp = PermFlag(normalize([p.perm[i-1] for i in s], t.N))
                    if subp == t:
                        t_flags.append(PermFlag(p.perm, list(s)))

            flags.append(t_flags)

        sys.stdout.write("\033[32mOK\033[m.\n")
        sys.stdout.flush()
        
        return flags
Exemplo n.º 10
0
    def _generate_flags(self):

        """Return list of lists of admissible flags for each type (one list of flags for each type)."""
        flags = list()

        for t in self.types:
            t_flags = list() # list of flags on type t
            tperm = t.perm
            m = int((self.N+t.N)/2) # must be casted as int
            rm = range(m)
            srm = Set(rm)
            petals = Permutations(m-t.N)
            subsets = Subsets(range(m), t.N) # will serve as values and positions
            cosubsets = [srm-s for s in subsets]
            for petal in petals: # now type and petal are both fixed
                for s in range(len(subsets)):
                    positions = subsets[s]
                    copositions = cosubsets[s]
                    for v in range(len(subsets)):
                        values = subsets[v]
                        covalues = cosubsets[v]

                        newflag = range(m)
                        for i in range(t.N):
                            newflag[positions[i]] = values[tperm[i]-1]+1
                        for j in range(m-t.N):
                            newflag[copositions[j]] = covalues[petal[j]-1]+1

                        if self._is_admissible(PermFlag(newflag)):
                            t_flags.append(PermFlag(newflag,list(subsets[s])))
                            
            flags.append(t_flags)

        return flags
Exemplo n.º 11
0
    def random_element(self):
        r"""
        Returns a random element of self.

        EXAMPLES::

            sage: M = PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd'))
            sage: M.an_element()
            [('a', 'b'), ('f', 'e'), ('c', 'd')]
            sage: all([PerfectMatchings(2*i).an_element() in PerfectMatchings(2*i)
            ...        for i in range(2,11,2)])
            True

        TESTS::

            sage: p = PerfectMatchings(13).random_element()
            Traceback (most recent call last):
            ...
            ValueError: there is no perfect matching on an odd number of elements

        """
        n = len(self._objects)

        if n % 2 == 1:
            raise ValueError("there is no perfect matching on an odd number of elements")

        k = n//2

        from sage.combinat.permutation import Permutations
        p = Permutations(n).random_element()

        return self([(self._objects[p[2*i]-1], self._objects[p[2*i+1]-1]) for i in range(k)])
Exemplo n.º 12
0
        def sum_of_partition_rearrangements(self, par):
            """
            Return the sum of all basis elements indexed by compositions which can be
            sorted to obtain a given partition.

            INPUT:

            - ``par`` -- a partition

            OUTPUT:

            - The sum of all ``self`` basis elements indexed by compositions
              which are permutations of ``par`` (without multiplicity).

            EXAMPLES::

                sage: NCSF=NonCommutativeSymmetricFunctions(QQ)
                sage: elementary = NCSF.elementary()
                sage: elementary.sum_of_partition_rearrangements(Partition([2,2,1]))
                L[1, 2, 2] + L[2, 1, 2] + L[2, 2, 1]
                sage: elementary.sum_of_partition_rearrangements(Partition([3,2,1]))
                L[1, 2, 3] + L[1, 3, 2] + L[2, 1, 3] + L[2, 3, 1] + L[3, 1, 2] + L[3, 2, 1]
                sage: elementary.sum_of_partition_rearrangements(Partition([]))
                L[]
            """
            return self.sum_of_monomials(
                self._basis_keys(comp) for comp in Permutations(par))
Exemplo n.º 13
0
def shard_poset(n):
    """
    Return the shard intersection order on permutations of size `n`.

    This is defined on the set of permutations. To every permutation,
    one can attach a pre-order, using the descending runs and their
    relative positions.

    The shard intersection order is given by the implication (or refinement)
    order on the set of pre-orders defined from all permutations.

    This can also be seen in a geometrical way. Every pre-order defines
    a cone in a vector space of dimension `n`. The shard poset is given by
    the inclusion of these cones.

    .. SEEALSO::

        :func:`shard_preorder_graph`

    EXAMPLES::

        sage: P = posets.ShardPoset(4); P  # indirect doctest
        Finite poset containing 24 elements
        sage: P.chain_polynomial()
        34*q^4 + 90*q^3 + 79*q^2 + 24*q + 1
        sage: P.characteristic_polynomial()
        q^3 - 11*q^2 + 23*q - 13
        sage: P.zeta_polynomial()
        17/3*q^3 - 6*q^2 + 4/3*q
        sage: P.is_selfdual()
        False
    """
    import operator
    Sn = [ShardPosetElement(s) for s in Permutations(n)]
    return Poset([Sn, operator.le], cover_relations=False, facade=True)
Exemplo n.º 14
0
    def n_simplex(self, dim_n=3, project=True):
        """
        Return a rational approximation to a regular simplex in
        dimension ``dim_n``.

        INPUT:

        - ``dim_n`` -- The dimension of the simplex, a positive
          integer.

        - ``project`` -- Optional argument, whether to project
          orthogonally.  Default is True.

        OUTPUT:

        A Polyhedron object of the ``dim_n``-dimensional simplex.

        EXAMPLES::

            sage: s5 = polytopes.n_simplex(5)
            sage: s5.dim()
            5
        """
        verts = Permutations([0 for i in range(dim_n)] + [1]).list()
        if project: verts = [Polytopes.project_1(x) for x in verts]
        return Polyhedron(vertices=verts)
Exemplo n.º 15
0
    def quantum_determinant(self, u=None):
        r"""
        Return the quantum determinant of ``self``.

        The quantum determinant is defined by:

        .. MATH::

            \operatorname{qdet}(u) = \sum_{\sigma \in S_n} (-1)^{\sigma}
            \prod_{k=1}^n T_{\sigma(k),k}(u - k + 1).

        EXAMPLES::

            sage: Y = Yangian(QQ, 2, 2)
            sage: Y.quantum_determinant()
            u^4 + (-2 + t(1)[1,1] + t(1)[2,2])*u^3
             + (1 - t(1)[1,1] + t(1)[1,1]*t(1)[2,2] - t(1)[1,2]*t(1)[2,1]
                - 2*t(1)[2,2] + t(2)[1,1] + t(2)[2,2])*u^2
             + (-t(1)[1,1]*t(1)[2,2] + t(1)[1,1]*t(2)[2,2]
                + t(1)[1,2]*t(1)[2,1] - t(1)[1,2]*t(2)[2,1]
                - t(1)[2,1]*t(2)[1,2] + t(1)[2,2] + t(1)[2,2]*t(2)[1,1]
                - t(2)[1,1] - t(2)[2,2])*u
             - t(1)[1,1]*t(2)[2,2] + t(1)[1,2]*t(2)[2,1] + t(2)[1,1]*t(2)[2,2]
                - t(2)[1,2]*t(2)[2,1] + t(2)[2,2]
        """
        if u is None:
            u = PolynomialRing(self.base_ring(), 'u').gen(0)
        from sage.combinat.permutation import Permutations
        n = self._n
        return sum(p.sign() * prod(
            self.defining_polynomial(p[k], k + 1, u - k) for k in range(n))
                   for p in Permutations(n))
Exemplo n.º 16
0
    def random_element(self):
        r"""
        Return a random element of ``self``.

        EXAMPLES::

            sage: M = PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd'))
            sage: M.random_element()
            [('a', 'b'), ('c', 'd'), ('e', 'f')]

        TESTS::

            sage: p = PerfectMatchings(13).random_element()
            Traceback (most recent call last):
            ...
            ValueError: there is no perfect matching on an odd number of elements
        """
        n = len(self._set)

        if n % 2 == 1:
            raise ValueError(
                "there is no perfect matching on an odd number of elements")

        k = n // 2
        p = Permutations(n).random_element()
        l = list(self._set)
        return self.element_class(self, [(l[p[2 * i] - 1], l[p[2 * i + 1] - 1])
                                         for i in range(k)],
                                  check=False)
Exemplo n.º 17
0
    def permutahedron(self, n, project=True):
        """
        The standard permutahedron of (1,...,n) projected into n-1
        dimensions.

        INPUT:

        - ``n`` -- the numbers ``(1,...,n)`` are permuted

        - ``project`` -- If ``False`` the polyhedron is left in dimension ``n``.

        OUTPUT:

        A Polyhedron object representing the permutahedron.

        EXAMPLES::

            sage: perm4 = polytopes.permutahedron(4)
            sage: perm4
            A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 24 vertices
            sage: polytopes.permutahedron(5).show()    # long time
            Graphics3d Object
        """
        verts = range(1, n + 1)
        verts = Permutations(verts).list()
        if project:
            verts = [Polytopes.project_1(x) for x in verts]
        p = Polyhedron(vertices=verts)
        return p
Exemplo n.º 18
0
    def hypersimplex(self, dim_n, k, project=True):
        """
        The hypersimplex in dimension dim_n with d choose k vertices,
        projected into (dim_n - 1) dimensions.

        INPUT:

        - ``n`` -- the numbers ``(1,...,n)`` are permuted

        - ``project`` -- If ``False``, the polyhedron is left in
          dimension ``n``.

        OUTPUT:

        A Polyhedron object representing the hypersimplex.

        EXAMPLES::

            sage: h_4_2 = polytopes.hypersimplex(4,2) # combinatorially equivalent to octahedron
            sage: h_4_2.n_vertices()
            6
            sage: h_4_2.n_inequalities()
            8
        """
        vert0 = [0] * (dim_n - k) + [1] * k
        verts = Permutations(vert0).list()
        if project:
            verts = [Polytopes.project_1(x) for x in verts]
        return Polyhedron(vertices=verts)
Exemplo n.º 19
0
def split_polyhedra(dim):
    r"""
    ::

        sage: from partitioner import split_polyhedra, repr_pretty_Hrepresentation

        sage: for P in split_polyhedra(2):
        ....:     print(repr_pretty_Hrepresentation(P, strict_inequality=True,
        ....:                                       prefix='s'))
        s1 > s0
        s0 >= s1

        sage: for P in split_polyhedra(3):
        ....:     print(repr_pretty_Hrepresentation(P, strict_inequality=True,
        ....:                                       prefix='s'))
        s1 >= s0, s2 > s1
        s2 > s0, s1 >= s2
        s2 > s0, s0 > s1
        s2 > s1, s0 >= s2
        s1 >= s0, s0 >= s2
        s1 >= s2, s0 > s1

        sage: for P in split_polyhedra(4):
        ....:     print(repr_pretty_Hrepresentation(P, strict_inequality=True,
        ....:                                       prefix='s'))
        s1 >= s0, s2 > s1, s3 > s2
        s1 >= s0, s3 > s1, s2 >= s3
        s2 >= s0, s3 > s1, s1 >= s2
        s2 >= s0, s3 > s2, s1 >= s3
        s3 > s0, s2 > s1, s1 >= s3
        s3 > s0, s2 >= s3, s1 >= s2
        s2 >= s0, s3 > s2, s0 > s1
        s3 > s0, s2 >= s3, s0 > s1
        s3 > s0, s2 > s1, s0 > s2
        s2 > s1, s3 > s2, s0 >= s3
        s2 >= s0, s3 > s1, s0 >= s3
        s3 > s1, s2 >= s3, s0 > s2
        s1 >= s0, s3 > s1, s0 > s2
        s3 > s0, s1 >= s3, s0 > s2
        s3 > s0, s1 >= s2, s0 > s1
        s3 > s1, s1 >= s2, s0 >= s3
        s1 >= s0, s3 > s2, s0 >= s3
        s3 > s2, s1 >= s3, s0 > s1
        s1 >= s0, s2 > s1, s0 >= s3
        s2 >= s0, s1 >= s2, s0 >= s3
        s2 >= s0, s1 >= s3, s0 > s1
        s2 > s1, s1 >= s3, s0 > s2
        s1 >= s0, s2 >= s3, s0 > s2
        s2 >= s3, s1 >= s2, s0 > s1
    """
    from sage.combinat.permutation import Permutations
    from sage.geometry.polyhedron.constructor import Polyhedron

    return iter(
        polyhedron_break_tie(
            Polyhedron(
                ieqs=[tuple(1 if i==b else (-1 if i==a else 0)
                            for i in range(dim+1))
                      for a, b in zip(pi[:-1], pi[1:])]))
        for pi in Permutations(dim))
Exemplo n.º 20
0
    def __iter__(self):
        """
        Return an iterator for parking functions of size `n`.

        .. warning::

            The precise order in which the parking function are
            generated is not fixed, and may change in the future.

        EXAMPLES::

            sage: PF = ParkingFunctions(0)
            sage: [e for e in PF]      # indirect doctest
            [[]]
            sage: PF = ParkingFunctions(1)
            sage: [e for e in PF]      # indirect doctest
            [[1]]
            sage: PF = ParkingFunctions(2)
            sage: [e for e in PF]      # indirect doctest
            [[1, 1], [1, 2], [2, 1]]
            sage: PF = ParkingFunctions(3)
            sage: [e for e in PF]      # indirect doctest
            [[1, 1, 1], [1, 1, 2], [1, 2, 1], [2, 1, 1], [1, 1, 3],
            [1, 3, 1], [3, 1, 1], [1, 2, 2], [2, 1, 2], [2, 2, 1],
            [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

        TESTS::

            sage: PF = ParkingFunctions(5)
            sage: [e for e in PF] == PF.list()
            True
            sage: PF = ParkingFunctions(6)
            sage: [e for e in PF] == PF.list()
            True
        """
        def iterator_rec(n):
            """
            TESTS::

                sage: PF = ParkingFunctions(2)
                sage: [e for e in PF]      # indirect doctest
                [[1, 1], [1, 2], [2, 1]]
            """
            if n == 0:
                yield []
                return
            if n == 1:
                yield [1]
                return
            for res1 in iterator_rec(n - 1):
                for i in range(res1[-1], n + 1):
                    res = copy(res1)
                    res.append(i)
                    yield res
            return

        for res in iterator_rec(self.n):
            for pi in Permutations(res):
                yield ParkingFunction(list(pi))
        return
Exemplo n.º 21
0
def PermutationsNK(n, k):
    r"""
    This is deprecated in :trac:`16472`. Use :class:`Permutations` instead
    (or ``itertools.permutations`` for iteration).

    EXAMPLES::

        sage: from sage.combinat.permutation_nk import PermutationsNK
        sage: P = PermutationsNK(10,4)
        doctest:...: DeprecationWarning: PermutationsNK is deprecated. Please
        use Permutations instead (or itertools.permutations for iteration).
        See http://trac.sagemath.org/16472 for details.
        sage: [ p for p in PermutationsNK(3,2)]
        [[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]]
        sage: PermutationsNK(3,2).cardinality()
        6
        sage: PermutationsNK(5,4).cardinality()
        120
    """
    from sage.misc.superseded import deprecation
    deprecation(
        16472,
        "PermutationsNK is deprecated. Please use Permutations instead (or itertools.permutations for iteration)."
    )
    from sage.combinat.permutation import Permutations
    return Permutations(range(n), k)
Exemplo n.º 22
0
        def to_symmetric_group_algebra_on_basis(self, S):
            """
            Return `D_S` as a linear combination of basis elements in the
            symmetric group algebra.

            EXAMPLES::

                sage: D = DescentAlgebra(QQ, 4).D()
                sage: [D.to_symmetric_group_algebra_on_basis(tuple(b))
                ....:  for b in Subsets(3)]
                [[1, 2, 3, 4],
                 [2, 1, 3, 4] + [3, 1, 2, 4] + [4, 1, 2, 3],
                 [1, 3, 2, 4] + [1, 4, 2, 3] + [2, 3, 1, 4]
                  + [2, 4, 1, 3] + [3, 4, 1, 2],
                 [1, 2, 4, 3] + [1, 3, 4, 2] + [2, 3, 4, 1],
                 [3, 2, 1, 4] + [4, 2, 1, 3] + [4, 3, 1, 2],
                 [2, 1, 4, 3] + [3, 1, 4, 2] + [3, 2, 4, 1]
                  + [4, 1, 3, 2] + [4, 2, 3, 1],
                 [1, 4, 3, 2] + [2, 4, 3, 1] + [3, 4, 2, 1],
                 [4, 3, 2, 1]]
            """
            n = self.realization_of()._n
            SGA = SymmetricGroupAlgebra(self.base_ring(), n)
            # Need to convert S to a list of positions by -1 for indexing
            P = Permutations(descents=([x - 1 for x in S], n))
            return SGA.sum_of_terms([(p, 1) for p in P])
Exemplo n.º 23
0
    def __init__(self, m, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = ZZ(m)
        self._n = ZZ(n)
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)

        if self._m == 1 or self._m == 2:
            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
            category = FiniteCoxeterGroups().Irreducible()
        else:
            from sage.categories.complex_reflection_groups import ComplexReflectionGroups
            category = ComplexReflectionGroups().Finite().Irreducible().WellGenerated()
        Parent.__init__(self, category=category)
Exemplo n.º 24
0
    def __iter__(self):
        r"""
        Efficient generation of Baxter permutations.

        OUTPUT:

        An iterator over the Baxter permutations of size ``self._n``.

        EXAMPLES::

            sage: BaxterPermutations(4).list()
            [[4, 3, 2, 1], [3, 4, 2, 1], [3, 2, 4, 1], [3, 2, 1, 4], [2, 4, 3, 1],
             [4, 2, 3, 1], [2, 3, 4, 1], [2, 3, 1, 4], [2, 1, 4, 3], [4, 2, 1, 3],
             [2, 1, 3, 4], [1, 4, 3, 2], [4, 1, 3, 2], [1, 3, 4, 2], [1, 3, 2, 4],
             [4, 3, 1, 2], [3, 4, 1, 2], [3, 1, 2, 4], [1, 2, 4, 3], [1, 4, 2, 3],
             [4, 1, 2, 3], [1, 2, 3, 4]]
            sage: [len(BaxterPermutations(n)) for n in range(9)]
            [1, 1, 2, 6, 22, 92, 422, 2074, 10754]

        TESTS::

            sage: all(a in BaxterPermutations(n) for n in range(7)
            ....:     for a in BaxterPermutations(n))
            True

        ALGORITHM:

        The algorithm using generating trees described in [BBMF2008]_ is used.
        The idea is that all Baxter permutations of size `n + 1` can be
        obtained by inserting the letter `n + 1` either just before a left
        to right maximum or just after a right to left maximum of a Baxter
        permutation of size `n`.
        """
        if self._n == 0:
            yield Permutations(0)([])
        elif self._n == 1:
            yield Permutations(1)([1])
        else:
            for b in BaxterPermutations(self._n - 1):
                # Left to right maxima.
                for j in b.reverse().saliances():
                    i = self._n - 2 - j
                    yield Permutations(self._n)(b[:i] + [self._n] + b[i:])
                # Right to left maxima.
                for i in b.saliances():
                    yield Permutations(self._n)(b[:i + 1] + [self._n] + b[i + 1:])
Exemplo n.º 25
0
    def product_on_basis(self, e_ij, e_kl):
        r"""
        Return the product of basis elements.

        EXAMPLES::

            sage: S = SchurAlgebra(QQ, 2, 3)
            sage: B = S.basis()

        If we multiply two basis elements `x` and `y`, such that
        `x[1]` and `y[0]` are not permutations of each other, the
        result is zero::

            sage: S.product_on_basis(((1, 1, 1), (1, 1, 2)), ((1, 2, 2), (1, 1, 2)))
            0

        If we multiply a basis element `x` by a basis element which
        consists of the same tuple repeated twice (on either side),
        the result is either zero (if the previous case applies) or `x`::

            sage: ww = B[((1, 2, 2), (1, 2, 2))]
            sage: x = B[((1, 2, 2), (1, 1, 2))]
            sage: ww * x
            S((1, 2, 2), (1, 1, 2))

        An arbitrary product, on the other hand, may have multiplicities::

            sage: x = B[((1, 1, 1), (1, 1, 2))]
            sage: y = B[((1, 1, 2), (1, 2, 2))]
            sage: x * y
            2*S((1, 1, 1), (1, 2, 2))
        """
        j = e_ij[1]

        i = e_ij[0]
        l = e_kl[1]

        l = sorted(l)

        # Find basis elements (p,q) such that p ~ i and q ~ l
        e_pq = []
        for v in self.basis().keys():
            if v[0] == i and sorted(v[1]) == l:
                e_pq.append(v)

        b = self.basis()
        product = self.zero()

        # Find s in I(n,r) such that (p,s) ~ (i,j) and (s,q) ~ (k,l)
        for e in e_pq:
            Z_ijklpq = self.base_ring().zero()
            for s in Permutations([xx for xx in j]):
                if (schur_representative_from_index(e[0], s) == e_ij
                        and schur_representative_from_index(s, e[1]) == e_kl):
                    Z_ijklpq += self.base_ring().one()
            product += Z_ijklpq * b[e]

        return product
Exemplo n.º 26
0
    def _element_constructor_(self, x):
        """
        Coerce x into self.

        EXAMPLES::

            sage: X = SchubertPolynomialRing(QQ)
            sage: X._element_constructor_([2,1,3])
            X[2, 1]
            sage: X._element_constructor_(Permutation([2,1,3]))
            X[2, 1]

            sage: R.<x1, x2, x3> = QQ[]
            sage: X(x1^2*x2)
            X[3, 2, 1]

        TESTS:

        We check that :trac:`12924` is fixed::

            sage: X = SchubertPolynomialRing(QQ)
            sage: X._element_constructor_([1,2,1])
            Traceback (most recent call last):
            ...
            ValueError: The input [1, 2, 1] is not a valid permutation
        """
        if isinstance(x, list):
            #checking the input to avoid symmetrica crashing Sage, see trac 12924
            if not x in Permutations():
                raise ValueError, "The input %s is not a valid permutation" % (
                    x)
            perm = permutation.Permutation_class(x).remove_extra_fixed_points()
            return self._from_dict({perm: self.base_ring()(1)})
        elif isinstance(x, permutation.Permutation_class):
            if not list(x) in Permutations():
                raise ValueError, "The input %s is not a valid permutation" % (
                    x)
            perm = x.remove_extra_fixed_points()
            return self._from_dict({perm: self.base_ring()(1)})
        elif is_MPolynomial(x):
            return symmetrica.t_POLYNOM_SCHUBERT(x)
        else:
            raise TypeError
Exemplo n.º 27
0
    def _structures(self, structure_class, labels):
        """
        EXAMPLES::

            sage: L = species.LinearOrderSpecies()
            sage: L.structures([1,2,3]).list()
            [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
        """
        from sage.combinat.permutation import Permutations
        for p in Permutations(len(labels)):
            yield structure_class(self, labels, p._list)
Exemplo n.º 28
0
                def on_basis(A):
                    k = A.size()
                    ret = R.zero()
                    if n < k:
                        return ret

                    for p in Permutations(k):
                        if P(p.to_cycles()) == A:
                            # -1 for indexing
                            ret += R.sum(prod(x[I[i]][I[p[i]-1]] for i in range(k))
                                         for I in Subsets(range(n), k))
                    return ret
Exemplo n.º 29
0
    def __init__(self, n):
        """
        EXAMPLES::

            sage: from sage.combinat.baxter_permutations import BaxterPermutations_size
            sage: BaxterPermutations_size(5)
            Baxter permutations of size 5
        """
        self.element_class = Permutations(n).element_class
        self._n = ZZ(n)
        from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
        super(BaxterPermutations, self).__init__(category=FiniteEnumeratedSets())
Exemplo n.º 30
0
    def __init__(self, d, n, q, R):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(5, 3)
            sage: elts = Y.some_elements() + list(Y.algebra_generators())
            sage: TestSuite(Y).run(elements=elts)
        """
        self._d = d
        self._n = n
        self._q = q
        self._Pn = Permutations(n)
        import itertools
        C = itertools.product(*([range(d)]*n))
        indices = list( itertools.product(C, self._Pn))
        cat = Algebras(R).WithBasis()
        CombinatorialFreeModule.__init__(self, R, indices, prefix='Y',
                                         category=cat)
        self._assign_names(self.algebra_generators().keys())
Exemplo n.º 31
0
    def _structures(self, structure_class, labels):
        """
        EXAMPLES::

            sage: P = species.PermutationSpecies()
            sage: P.structures([1,2,3]).list()
            [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
        """
        if labels == []:
            yield structure_class(self, labels, [])
        else:
            for p in Permutations(len(labels)):
                yield structure_class(self, labels, list(p))
Exemplo n.º 32
0
    def __init__(self, m, n, category=None):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = m
        self._n = n
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)
        if category is None:
            category = (Groups(), FiniteEnumeratedSets())
        Parent.__init__(self, category=category)
Exemplo n.º 33
0
class YokonumaHeckeAlgebra(CombinatorialFreeModule):
    r"""
    The Yokonuma-Hecke algebra `Y_{d,n}(q)`.

    Let `R` be a commutative ring and `q` be a unit in `R`. The
    *Yokonuma-Hecke algebra* `Y_{d,n}(q)` is the associative, unital
    `R`-algebra generated by `t_1, t_2, \ldots, t_n, g_1, g_2, \ldots,
    g_{n-1}` and subject to the relations:

    - `g_i g_j = g_j g_i` for all `|i - j| > 1`,
    - `g_i g_{i+1} g_i = g_{i+1} g_i g_{i+1}`,
    - `t_i t_j = t_j t_i`,
    - `t_j g_i = g_i t_{j s_i}`, and
    - `t_j^d = 1`,

    where `s_i` is the simple transposition `(i, i+1)`, along with
    the quadratic relation

    .. MATH::

        g_i^2 = 1 + \frac{(q - q^{-1})}{d} \left( \sum_{s=0}^{d-1}
        t_i^s t_{i+1}^{-s} \right) g_i.

    Thus the Yokonuma-Hecke algebra can be considered a quotient of
    the framed braid group `(\ZZ / d\ZZ) \wr B_n`, where `B_n` is the
    classical braid group on `n` strands, by the quadratic relations.
    Moreover, all of the algebra generators are invertible. In
    particular, we have

    .. MATH::

        g_i^{-1} = g_i - (q - q^{-1}) e_i.

    When we specialize `q = \pm 1`, we obtain the group algebra of
    the complex reflection group `G(d, 1, n) = (\ZZ / d\ZZ) \wr S_n`.
    Moreover for `d = 1`, the Yokonuma-Hecke algebra is equal to the
    :class:`Iwahori-Hecke <IwahoriHeckeAlgebra>` of type `A_{n-1}`.

    INPUT:

    - ``d`` -- the maximum power of `t`
    - ``n`` -- the number of generators
    - ``q`` -- (optional) an invertible element in a commutative ring;
      the default is `q \in \QQ[q,q^{-1}]`
    - ``R`` -- (optional) a commutative ring containing ``q``; the
      default is the parent of `q`

    EXAMPLES:

    We construct `Y_{4,3}` and do some computations::

        sage: Y = algebras.YokonumaHecke(4, 3)
        sage: g1, g2, t1, t2, t3 = Y.algebra_generators()
        sage: g1 * g2
        g[1,2]
        sage: t1 * g1
        t1*g[1]
        sage: g2 * t2
        t3*g[2]
        sage: g2 * t3
        t2*g[2]
        sage: (g2 + t1) * (g1 + t2*t3)
        g[2,1] + t2*t3*g[2] + t1*g[1] + t1*t2*t3
        sage: g1 * g1
        1 - (1/4*q^-1-1/4*q)*g[1] - (1/4*q^-1-1/4*q)*t1*t2^3*g[1]
         - (1/4*q^-1-1/4*q)*t1^2*t2^2*g[1] - (1/4*q^-1-1/4*q)*t1^3*t2*g[1]
        sage: g2 * g1 * t1
        t3*g[2,1]

    We construct the elements `e_i` and show that they are idempotents::

        sage: e1 = Y.e(1); e1
        1/4 + 1/4*t1*t2^3 + 1/4*t1^2*t2^2 + 1/4*t1^3*t2
        sage: e1 * e1 == e1
        True
        sage: e2 = Y.e(2); e2
        1/4 + 1/4*t2*t3^3 + 1/4*t2^2*t3^2 + 1/4*t2^3*t3
        sage: e2 * e2 == e2
        True

    REFERENCES:

    - [CL2013]_

    - [CPdA2014]_

    - [ERH2015]_

    - [JPdA15]_
    """
    @staticmethod
    def __classcall_private__(cls, d, n, q=None, R=None):
        """
        Standardize input to ensure a unique representation.

        TESTS::

            sage: Y1 = algebras.YokonumaHecke(5, 3)
            sage: q = LaurentPolynomialRing(QQ, 'q').gen()
            sage: Y2 = algebras.YokonumaHecke(5, 3, q)
            sage: Y3 = algebras.YokonumaHecke(5, 3, q, q.parent())
            sage: Y1 is Y2 and Y2 is Y3
            True
        """
        if q is None:
            q = LaurentPolynomialRing(QQ, 'q').gen()
        if R is None:
            R = q.parent()
        q = R(q)
        if R not in Rings().Commutative():
            raise TypeError("base ring must be a commutative ring")
        return super(YokonumaHeckeAlgebra, cls).__classcall__(cls, d, n, q, R)

    def __init__(self, d, n, q, R):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(5, 3)
            sage: elts = Y.some_elements() + list(Y.algebra_generators())
            sage: TestSuite(Y).run(elements=elts)
        """
        self._d = d
        self._n = n
        self._q = q
        self._Pn = Permutations(n)
        import itertools
        C = itertools.product(*([range(d)]*n))
        indices = list( itertools.product(C, self._Pn))
        cat = Algebras(R).WithBasis()
        CombinatorialFreeModule.__init__(self, R, indices, prefix='Y',
                                         category=cat)
        self._assign_names(self.algebra_generators().keys())

    def _repr_(self):
        """ 
        Return a string representation of ``self``.

        EXAMPLES::

            sage: algebras.YokonumaHecke(5, 2)
            Yokonuma-Hecke algebra of rank 5 and order 2 with q=q
             over Univariate Laurent Polynomial Ring in q over Rational Field
        """
        return "Yokonuma-Hecke algebra of rank {} and order {} with q={} over {}".format(
            self._d, self._n, self._q, self.base_ring())

    def _latex_(self):
        r"""
        Return a latex representation of ``self``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(5, 2)
            sage: latex(Y)
            \mathcal{Y}_{5,2}(q)
        """
        return "\\mathcal{Y}_{%s,%s}(%s)"%(self._d, self._n, self._q)

    def _repr_term(self, m):
        """
        Return a string representation of the basis element indexed by ``m``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(4, 3)
            sage: Y._repr_term( ((1, 0, 2), Permutation([3,2,1])) )
            't1*t3^2*g[2,1,2]'
        """
        gen_str = lambda e: '' if e == 1 else '^%s'%e
        lhs = '*'.join('t%s'%(j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0)
        redword = m[1].reduced_word()
        if not redword:
            if not lhs:
                return '1'
            return lhs
        rhs = 'g[{}]'.format(','.join(str(i) for i in redword))
        if not lhs:
            return rhs
        return lhs + '*' + rhs

    def _latex_term(self, m):
        r"""
        Return a latex representation for the basis element indexed by ``m``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(4, 3)
            sage: Y._latex_term( ((1, 0, 2), Permutation([3,2,1])) )
            't_{1} t_{3}^2 g_{2} g_{1} g_{2}'
        """
        gen_str = lambda e: '' if e == 1 else '^%s'%e
        lhs = ' '.join('t_{%s}'%(j+1) + gen_str(i) for j,i in enumerate(m[0]) if i > 0)
        redword = m[1].reduced_word()
        if not redword:
            if not lhs:
                return '1'
            return lhs
        return lhs + ' ' + ' '.join("g_{%d}"%i for i in redword)

    @cached_method
    def algebra_generators(self):
        """
        Return the algebra generators of ``self``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(5, 3)
            sage: dict(Y.algebra_generators())
            {'g1': g[1], 'g2': g[2], 't1': t1, 't2': t2, 't3': t3}
        """
        one = self._Pn.one()
        zero = [0]*self._n
        d = {}
        for i in range(self._n):
            r = list(zero) # Make a copy
            r[i] = 1
            d['t%s'%(i+1)] = self.monomial( (tuple(r), one) )
        G = self._Pn.group_generators()
        for i in range(1, self._n):
            d['g%s'%i] = self.monomial( (tuple(zero), G[i]) )
        return Family(sorted(d), lambda i: d[i])

    @cached_method
    def gens(self):
        """
        Return the generators of ``self``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(5, 3)
            sage: Y.gens()
            (g[1], g[2], t1, t2, t3)
        """
        return tuple(self.algebra_generators())

    @cached_method
    def one_basis(self):
        """
        Return the index of the basis element of `1`.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(5, 3)
            sage: Y.one_basis()
            ((0, 0, 0), [1, 2, 3])
        """
        one = self._Pn.one()
        zero = [0]*self._n
        return (tuple(zero), one)

    @cached_method
    def e(self, i):
        """
        Return the element `e_i`.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(4, 3)
            sage: Y.e(1)
            1/4 + 1/4*t1*t2^3 + 1/4*t1^2*t2^2 + 1/4*t1^3*t2
            sage: Y.e(2)
            1/4 + 1/4*t2*t3^3 + 1/4*t2^2*t3^2 + 1/4*t2^3*t3
        """
        if i < 1 or i >= self._n:
            raise ValueError("invalid index")
        c = ~self.base_ring()(self._d)
        zero = [0]*self._n
        one = self._Pn.one()
        d = {}
        for s in range(self._d):
            r = list(zero) # Make a copy
            r[i-1] = s
            if s != 0:
                r[i] = self._d - s
            d[(tuple(r), one)] = c
        return self._from_dict(d, remove_zeros=False)

    def g(self, i=None):
        """
        Return the generator(s) `g_i`.

        INPUT:

        - ``i`` -- (default: ``None``) the generator `g_i` or if ``None``,
          then the list of all generators `g_i`

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(8, 3)
            sage: Y.g(1)
            g[1]
            sage: Y.g()
            [g[1], g[2]]
        """
        G = self.algebra_generators()
        if i is None:
            return [G['g%s'%i] for i in range(1, self._n)]
        return G['g%s'%i]

    def t(self, i=None):
        """
        Return the generator(s) `t_i`.

        INPUT:

        - ``i`` -- (default: ``None``) the generator `t_i` or if ``None``,
          then the list of all generators `t_i`

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(8, 3)
            sage: Y.t(2)
            t2
            sage: Y.t()
            [t1, t2, t3]
        """
        G = self.algebra_generators()
        if i is None:
            return [G['t%s'%i] for i in range(1, self._n+1)]
        return G['t%s'%i]

    def product_on_basis(self, m1, m2):
        """
        Return the product of the basis elements indexed by ``m1`` and ``m2``.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(4, 3)
            sage: m = ((1, 0, 2), Permutations(3)([2,1,3]))
            sage: 4 * Y.product_on_basis(m, m)
            -(q^-1-q)*t2^2*g[1] + 4*t1*t2 - (q^-1-q)*t1*t2*g[1]
             - (q^-1-q)*t1^2*g[1] - (q^-1-q)*t1^3*t2^3*g[1]

        Check that we apply the permutation correctly on `t_i`::

            sage: Y = algebras.YokonumaHecke(4, 3)
            sage: g1, g2, t1, t2, t3 = Y.algebra_generators()
            sage: g21 = g2 * g1
            sage: g21 * t1
            t3*g[2,1]
        """
        t1,g1 = m1
        t2,g2 = m2
        # Commmute g1 and t2, then multiply t1 and t2
        #ig1 = g1
        t = [(t1[i] + t2[g1.index(i+1)]) % self._d for i in range(self._n)]
        one = self._Pn.one()
        if g1 == one:
            return self.monomial((tuple(t), g2))
        ret = self.monomial((tuple(t), g1))
        # We have to reverse the reduced word due to Sage's convention
        #   for permutation multiplication
        for i in g2.reduced_word():
            ret = self.linear_combination((self._product_by_basis_gen(m, i), c)
                                          for m,c in ret)
        return ret

    def _product_by_basis_gen(self, m, i):
        r"""
        Return the product `t g_w g_i`.

        If the quadratic relation is `g_i^2 = 1 + (q + q^{-1})e_i g_i`,
        then we have

        .. MATH::

            g_w g_i = \begin{cases}
            g_{ws_i} & \text{if } \ell(ws_i) = \ell(w) + 1, \\
            g_{ws_i} - (q - q^{-1}) g_w e_i & \text{if }
            \ell(w s_i) = \ell(w) - 1.
            \end{cases}

        INPUT:

        - ``m`` -- a pair ``[t, w]``, where ``t`` encodes the monomial
          and ``w``  is an element of the permutation group
        - ``i`` -- an element of the index set

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(4, 3)
            sage: m = ((1, 0, 2), Permutations(3)([2,1,3]))
            sage: 4 * Y._product_by_basis_gen(m, 1)
            -(q^-1-q)*t2*t3^2*g[1] + 4*t1*t3^2 - (q^-1-q)*t1*t3^2*g[1]
             - (q^-1-q)*t1^2*t2^3*t3^2*g[1] - (q^-1-q)*t1^3*t2^2*t3^2*g[1]
        """
        t, w = m
        # We have to flip the side due to Sage's multiplication
        #   convention for permutations
        wi = w.apply_simple_reflection(i, side="left")
        if not w.has_descent(i, side="left"):
            return self.monomial((t, wi))

        R = self.base_ring()
        c = (self._q - ~self._q) * ~R(self._d)
        d = {(t, wi): R.one()}
        # We commute g_w and e_i and then multiply by t
        for s in range(self._d):
            r = list(t)
            r[w[i-1]-1] = (r[w[i-1]-1] + s) % self._d
            if s != 0:
                r[w[i]-1] = (r[w[i]-1] + self._d - s) % self._d
            d[(tuple(r), w)] = c
        return self._from_dict(d, remove_zeros=False)

    @cached_method
    def inverse_g(self, i):
        r"""
        Return the inverse of the generator `g_i`.

        From the quadratic relation, we have

        .. MATH::

            g_i^{-1} = g_i - (q - q^{-1}) e_i.

        EXAMPLES::

            sage: Y = algebras.YokonumaHecke(2, 4)
            sage: [2*Y.inverse_g(i) for i in range(1, 4)]
            [(q^-1+q) + 2*g[1] + (q^-1+q)*t1*t2,
             (q^-1+q) + 2*g[2] + (q^-1+q)*t2*t3,
             (q^-1+q) + 2*g[3] + (q^-1+q)*t3*t4]
        """
        if i < 1 or i >= self._n:
            raise ValueError("invalid index")
        return self.g(i) + (~self._q + self._q) * self.e(i)

    class Element(CombinatorialFreeModule.Element):
        def inverse(self):
            r"""
            Return the inverse if ``self`` is a basis element.

            EXAMPLES::

                sage: Y = algebras.YokonumaHecke(3, 3)
                sage: t = prod(Y.t()); t
                t1*t2*t3
                sage: ~t
                t1^2*t2^2*t3^2
                sage: [3*~(t*g) for g in Y.g()]
                [(q^-1+q)*t2*t3^2 + (q^-1+q)*t1*t3^2
                   + (q^-1+q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[1],
                 (q^-1+q)*t1^2*t3 + (q^-1+q)*t1^2*t2
                   + (q^-1+q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[2]]
            """
            if len(self) != 1:
                raise NotImplementedError("inverse only implemented for basis elements (monomials in the generators)"%self)
            H = self.parent()
            t,w = self.support_of_term()
            telt = H.monomial( (tuple((H._d - e) % H._d for e in t), H._Pn.one()) )
            return telt * H.prod(H.inverse_g(i) for i in reversed(w.reduced_word()))

        __invert__ = inverse
Exemplo n.º 34
0
class ColoredPermutations(Parent, UniqueRepresentation):
    r"""
    The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`.

    Let `S_n` be the symmetric group on `n` letters and `C_m` be the cyclic
    group of order `m`. The `m`-colored permutation group on `n` letters
    is given by `P_n^m = C_m \wr S_n`. This is also the complex reflection
    group `G(m, 1, n)`.

    We define our multiplication by

    .. MATH::

        ((s_1, \ldots s_n), \sigma) \cdot ((t_1, \ldots, t_n), \tau)
        = ((s_1 t_{\sigma(1)}, \ldots, s_n t_{\sigma(n)}), \tau \sigma).

    EXAMPLES::

        sage: C = ColoredPermutations(4, 3); C
        4-colored permutations of size 3
        sage: s1,s2,t = C.gens()
        sage: (s1, s2, t)
        ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]])
        sage: s1*s2
        [[0, 0, 0], [3, 1, 2]]
        sage: s1*s2*s1 == s2*s1*s2
        True
        sage: t^4 == C.one()
        True
        sage: s2*t*s2
        [[0, 1, 0], [1, 2, 3]]

    We can also create a colored permutation by passing
    either a list of tuples consisting of ``(color, element)``::

        sage: x = C([(2,1), (3,3), (3,2)]); x
        [[2, 3, 3], [1, 3, 2]]

    or a list of colors and a permutation::

        sage: C([[3,3,1], [1,3,2]])
        [[3, 3, 1], [1, 3, 2]]

    There is also the natural lift from permutations::

        sage: P = Permutations(3)
        sage: C(P.an_element())
        [[0, 0, 0], [3, 1, 2]]

    REFERENCES:

    - :wikipedia:`Generalized_symmetric_group`
    - :wikipedia:`Complex_reflection_group`
    """
    def __init__(self, m, n):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(2, 3)
            sage: TestSuite(C).run()
            sage: C = ColoredPermutations(1, 3)
            sage: TestSuite(C).run()
        """
        if m <= 0:
            raise ValueError("m must be a positive integer")
        self._m = ZZ(m)
        self._n = ZZ(n)
        self._C = IntegerModRing(self._m)
        self._P = Permutations(self._n)

        if self._m == 1 or self._m == 2:
            from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups
            category = FiniteCoxeterGroups().Irreducible()
        else:
            from sage.categories.complex_reflection_groups import ComplexReflectionGroups
            category = ComplexReflectionGroups().Finite().Irreducible().WellGenerated()
        Parent.__init__(self, category=category)

    def _repr_(self):
        """
        Return a string representation of ``self``.

        EXAMPLES::

            sage: ColoredPermutations(4, 3)
            4-colored permutations of size 3
        """
        return "{}-colored permutations of size {}".format(self._m, self._n)

    @cached_method
    def index_set(self):
        """
        Return the index set of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(3, 4)
            sage: C.index_set()
            (1, 2, 3, 4)

            sage: C = ColoredPermutations(1, 4)
            sage: C.index_set()
            (1, 2, 3)

        TESTS::

            sage: S = SignedPermutations(4)
            sage: S.index_set()
            (1, 2, 3, 4)
        """
        n = self._n
        if self._m != 1:
            n += 1
        return tuple(range(1, n))

    def coxeter_matrix(self):
        """
        Return the Coxeter matrix of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(3, 4)
            sage: C.coxeter_matrix()
            [1 3 2 2]
            [3 1 3 2]
            [2 3 1 4]
            [2 2 4 1]

            sage: C = ColoredPermutations(1, 4)
            sage: C.coxeter_matrix()
            [1 3 2]
            [3 1 3]
            [2 3 1]

        TESTS::

            sage: S = SignedPermutations(4)
            sage: S.coxeter_matrix()
            [1 3 2 2]
            [3 1 3 2]
            [2 3 1 4]
            [2 2 4 1]
        """
        from sage.combinat.root_system.cartan_type import CartanType
        if self._m == 1:
            return CartanType(['A', self._n-1]).coxeter_matrix()
        return CartanType(['B', self._n]).coxeter_matrix()

    @cached_method
    def one(self):
        """
        Return the identity element of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.one()
            [[0, 0, 0], [1, 2, 3]]
        """
        return self.element_class(self, [self._C.zero()] * self._n,
                                  self._P.identity())

    def simple_reflection(self, i):
        r"""
        Return the ``i``-th simple reflection of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.gens()
            ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]])
            sage: C.simple_reflection(2)
            [[0, 0, 0], [1, 3, 2]]
            sage: C.simple_reflection(3)
            [[0, 0, 1], [1, 2, 3]]

            sage: S = SignedPermutations(4)
            sage: S.simple_reflection(1)
            [2, 1, 3, 4]
            sage: S.simple_reflection(4)
            [1, 2, 3, -4]
        """
        if i not in self.index_set():
            raise ValueError("i must be in the index set")
        colors = [self._C.zero()] * self._n
        if i < self._n:
            p = list(range(1, self._n + 1))
            p[i - 1] = i + 1
            p[i] = i
            return self.element_class(self, colors, self._P(p))
        colors[-1] = self._C.one()
        return self.element_class(self, colors, self._P.identity())

    @cached_method
    def _inverse_simple_reflections(self):
        """
        Return the inverse of the simple reflections of ``self``.

        .. WARNING::

            This returns a ``dict`` that should not be mutated since
            the result is cached.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C._inverse_simple_reflections()
            {1: [[0, 0, 0], [2, 1, 3]],
             2: [[0, 0, 0], [1, 3, 2]],
             3: [[0, 0, 3], [1, 2, 3]]}
        """
        s = self.simple_reflections()
        return {i: ~s[i] for i in self.index_set()}

    @cached_method
    def gens(self):
        """
        Return the generators of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.gens()
            ([[0, 0, 0], [2, 1, 3]],
             [[0, 0, 0], [1, 3, 2]],
             [[0, 0, 1], [1, 2, 3]])

            sage: S = SignedPermutations(4)
            sage: S.gens()
            ([2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3], [1, 2, 3, -4])
        """
        return tuple(self.simple_reflection(i) for i in self.index_set())

    def matrix_group(self):
        """
        Return the matrix group corresponding to ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.matrix_group()
            Matrix group over Cyclotomic Field of order 4 and degree 2 with 3 generators (
            [0 1 0]  [1 0 0]  [    1     0     0]
            [1 0 0]  [0 0 1]  [    0     1     0]
            [0 0 1], [0 1 0], [    0     0 zeta4]
            )
        """
        from sage.groups.matrix_gps.finitely_generated import MatrixGroup
        return MatrixGroup([g.to_matrix() for g in self.gens()])

    def _element_constructor_(self, x):
        """
        Construct an element of ``self`` from ``x``.

        INPUT:

        Either a list of pairs (color, element)
        or a pair of lists (colors, elements).

        TESTS::

            sage: C = ColoredPermutations(4, 3)
            sage: x = C([(2,1), (3,3), (3,2)]); x
            [[2, 3, 3], [1, 3, 2]]
            sage: x == C([[2,3,3], [1,3,2]])
            True
        """
        if isinstance(x, list):
            if isinstance(x[0], tuple):
                c = []
                p = []
                for k in x:
                    if len(k) != 2:
                        raise ValueError("input must be pairs (color, element)")
                    c.append(self._C(k[0]))
                    p.append(k[1])
                return self.element_class(self, c, self._P(p))

            if len(x) != 2:
                raise ValueError("input must be a pair of a list of colors and a permutation")
            return self.element_class(self, [self._C(v) for v in x[0]], self._P(x[1]))

    def _coerce_map_from_(self, C):
        """
        Return a coerce map from ``C`` if it exists and ``None`` otherwise.

        EXAMPLES::

            sage: C = ColoredPermutations(2, 3)
            sage: S = SignedPermutations(3)
            sage: C.has_coerce_map_from(S)
            True

            sage: C = ColoredPermutations(4, 3)
            sage: C.has_coerce_map_from(S)
            False
            sage: S = SignedPermutations(4)
            sage: C.has_coerce_map_from(S)
            False

            sage: P = Permutations(3)
            sage: C.has_coerce_map_from(P)
            True
            sage: P = Permutations(4)
            sage: C.has_coerce_map_from(P)
            False
        """
        if isinstance(C, Permutations) and C.n == self._n:
            return lambda P, x: P.element_class(P, [P._C.zero()]*P._n, x)
        if self._m == 2 and isinstance(C, SignedPermutations) and C._n == self._n:
            return lambda P, x: P.element_class(P,
                                                [P._C.zero() if v == 1 else P._C.one()
                                                 for v in x._colors],
                                                x._perm)
        return super(ColoredPermutations, self)._coerce_map_from_(C)

    def __iter__(self):
        """
        Iterate over ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(2, 2)
            sage: [x for x in C]
            [[[0, 0], [1, 2]],
             [[0, 1], [1, 2]],
             [[1, 0], [1, 2]],
             [[1, 1], [1, 2]],
             [[0, 0], [2, 1]],
             [[0, 1], [2, 1]],
             [[1, 0], [2, 1]],
             [[1, 1], [2, 1]]]
        """
        for p in self._P:
            for c in itertools.product(self._C, repeat=self._n):
                yield self.element_class(self, c, p)

    def cardinality(self):
        """
        Return the cardinality of ``self``.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.cardinality()
            384
            sage: C.cardinality() == 4**3 * factorial(3)
            True
        """
        return self._m ** self._n * self._P.cardinality()

    order = cardinality

    def rank(self):
        """
        Return the rank of ``self``.

        The rank of a complex reflection group is equal to the dimension
        of the complex vector space the group acts on.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 12)
            sage: C.rank()
            12
            sage: C = ColoredPermutations(7, 4)
            sage: C.rank()
            4
            sage: C = ColoredPermutations(1, 4)
            sage: C.rank()
            3
        """
        if self._m == 1:
            return self._n - 1
        return self._n

    def degrees(self):
        """
        Return the degrees of ``self``.

        The degrees of a complex reflection group are the degrees of
        the fundamental invariants of the ring of polynomial invariants.

        If `m = 1`, then we are in the special case of the symmetric group
        and the degrees are `(2, 3, \ldots, n, n+1)`. Otherwise the degrees
        are `(m, 2m, \ldots, nm)`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.degrees()
            (4, 8, 12)
            sage: S = ColoredPermutations(1, 3)
            sage: S.degrees()
            (2, 3)

        We now check that the product of the degrees is equal to the
        cardinality of ``self``::

            sage: prod(C.degrees()) == C.cardinality()
            True
            sage: prod(S.degrees()) == S.cardinality()
            True
        """
        # For the usual symmetric group (self._m=1) we need to start at 2
        start = 2 if self._m == 1 else 1
        return tuple(self._m * i for i in range(start, self._n + 1))

    def codegrees(self):
        r"""
        Return the codegrees of ``self``.

        Let `G` be a complex reflection group. The codegrees
        `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be
        defined by:

        .. MATH::

            \prod_{i=1}^{\ell} (q - d_i^* - 1)
            = \sum_{g \in G} \det(g) q^{\dim(V^g)},

        where `V` is the natural complex vector space that `G` acts on
        and `\ell` is the :meth:`rank`.

        If `m = 1`, then we are in the special case of the symmetric group
        and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees
        are `((n-1)m, (n-2)m, \ldots, m, 0)`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.codegrees()
            (8, 4, 0)
            sage: S = ColoredPermutations(1, 3)
            sage: S.codegrees()
            (1, 0)

        TESTS:

        We check the polynomial identity::

            sage: R.<q> = ZZ[]
            sage: C = ColoredPermutations(3, 2)
            sage: f = prod(q - ds - 1 for ds in C.codegrees())
            sage: d = lambda x: sum(1 for e in x.to_matrix().eigenvalues() if e == 1)
            sage: g = sum(det(x.to_matrix()) * q**d(x) for x in C)
            sage: f == g
            True
        """
        # Special case for the usual symmetric group
        last = self._n-1 if self._m == 1 else self._n
        return tuple(self._m * i for i in reversed(range(last)))

    def number_of_reflection_hyperplanes(self):
        """
        Return the number of reflection hyperplanes of ``self``.

        The number of reflection hyperplanes of a complex reflection
        group is equal to the sum of the codegrees plus the rank.

        EXAMPLES::

            sage: C = ColoredPermutations(1, 2)
            sage: C.number_of_reflection_hyperplanes()
            1
            sage: C = ColoredPermutations(1, 3)
            sage: C.number_of_reflection_hyperplanes()
            3
            sage: C = ColoredPermutations(4, 12)
            sage: C.number_of_reflection_hyperplanes()
            276
        """
        return sum(self.codegrees()) + self.rank()

    def fixed_point_polynomial(self, q=None):
        r"""
        The fixed point polynomial of ``self``.

        The fixed point polynomial `f_G` of a complex reflection group `G`
        is counting the dimensions of fixed points subspaces:

        .. MATH::

            f_G(q) = \sum_{w \in W} q^{\dim V^w}.

        Furthermore, let `d_1, d_2, \ldots, d_{\ell}` be the degrees of `G`,
        where `\ell` is the :meth:`rank`. Then the fixed point polynomial
        is given by

        .. MATH::

            f_G(q) = \prod_{i=1}^{\ell} (q + d_i - 1).

        INPUT:

        - ``q`` -- (default: the generator of ``ZZ['q']``) the parameter `q`

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.fixed_point_polynomial()
            q^3 + 21*q^2 + 131*q + 231

            sage: S = ColoredPermutations(1, 3)
            sage: S.fixed_point_polynomial()
            q^2 + 3*q + 2

        TESTS:

        We check the against the degrees and codegrees::

            sage: R.<q> = ZZ[]
            sage: C = ColoredPermutations(4, 3)
            sage: C.fixed_point_polynomial(q) == prod(q + d - 1 for d in C.degrees())
            True
        """
        if q is None:
            q = PolynomialRing(ZZ, 'q').gen(0)
        return prod(q + d - 1 for d in self.degrees())

    def is_well_generated(self):
        """
        Return if ``self`` is a well-generated complex reflection group.

        A complex reflection group `G` is well-generated if it is
        generated by `\ell` reflections. Equivalently, `G` is well-generated
        if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell`.

        EXAMPLES::

            sage: C = ColoredPermutations(4, 3)
            sage: C.is_well_generated()
            True
            sage: C = ColoredPermutations(2, 8)
            sage: C.is_well_generated()
            True
            sage: C = ColoredPermutations(1, 4)
            sage: C.is_well_generated()
            True
        """
        deg = self.degrees()
        dstar = self.codegrees()
        return all(deg[-1] == d + dstar[i] for i, d in enumerate(deg))

    Element = ColoredPermutation