Пример #1
0
    def divided_difference(self, i):
        """
        EXAMPLES::

            sage: X = SchubertPolynomialRing(ZZ)
            sage: a = X([3,2,1])
            sage: a.divided_difference(1)
            X[2, 3, 1]
            sage: a.divided_difference([3,2,1])
            X[1]
        """
        if isinstance(i, Integer):
            return symmetrica.divdiff_schubert(i, self)
        elif i in permutation.Permutations():
            return symmetrica.divdiff_perm_schubert(i, self)
        else:
            raise TypeError, "i must either be an integer or permutation"
Пример #2
0
 def divided_difference(self, i):
     """
     EXAMPLES::
     
         sage: X = SchubertPolynomialRing(ZZ)
         sage: a = X([3,2,1])
         sage: a.divided_difference(1)
         X[2, 3, 1]
         sage: a.divided_difference([3,2,1])
         X[1]
     """
     if isinstance(i, Integer):
         return symmetrica.divdiff_schubert(i, self)
     elif i in permutation.Permutations():
         return symmetrica.divdiff_perm_schubert(i, self)
     else:
         raise TypeError, "i must either be an integer or permutation"
Пример #3
0
    def divided_difference(self, i, algorithm="sage"):
        r"""
        Return the ``i``-th divided difference operator, applied to ``self``.

        Here, ``i`` can be either a permutation or a positive integer.

        INPUT:

        - ``i`` -- permutation or positive integer

        - ``algorithm`` -- (default: ``'sage'``) either ``'sage'``
          or ``'symmetrica'``; this determines which software is
          called for the computation

        OUTPUT:

        The result of applying the ``i``-th divided difference
        operator to ``self``.

        If `i` is a positive integer, then the `i`-th divided
        difference operator `\delta_i` is the linear operator sending
        each polynomial `f = f(x_1, x_2, \ldots, x_n)` (in
        `n \geq i+1` variables) to the polynomial

        .. MATH::

            \frac{f - f_i}{x_i - x_{i+1}}, \qquad \text{ where }
            f_i = f(x_1, x_2, ..., x_{i-1}, x_{i+1}, x_i,
            x_{i+1}, ..., x_n) .

        If `\sigma` is a permutation in the `n`-th symmetric group,
        then the `\sigma`-th divided difference operator `\delta_\sigma`
        is the composition
        `\delta_{i_1} \delta_{i_2} \cdots \delta_{i_k}`, where
        `\sigma = s_{i_1} \circ s_{i_2} \circ \cdots \circ s_{i_k}` is
        any reduced expression for `\sigma` (the precise choice of
        reduced expression is immaterial).

        .. NOTE::

            The :meth:`expand` method results in a polynomial
            in `n` variables named ``x0, x1, ..., x(n-1)`` rather than
            `x_1, x_2, \ldots, x_n`.
            The variable named ``xi`` corresponds to `x_{i+1}`.
            Thus, ``self.divided_difference(i)`` involves the variables
            ``x(i-1)`` and ``xi`` getting switched (in the numerator).

        EXAMPLES::

            sage: X = SchubertPolynomialRing(ZZ)
            sage: a = X([3,2,1])
            sage: a.divided_difference(1)
            X[2, 3, 1]
            sage: a.divided_difference([3,2,1])
            X[1]
            sage: a.divided_difference(5)
            0

        Any divided difference of `0` is `0`::

            sage: X.zero().divided_difference(2)
            0

        This is compatible when a permutation is given as input::

            sage: a = X([3,2,4,1])
            sage: a.divided_difference([2,3,1])
            0
            sage: a.divided_difference(1).divided_difference(2)
            0

        ::

            sage: a = X([4,3,2,1])
            sage: a.divided_difference([2,3,1])
            X[3, 2, 4, 1]
            sage: a.divided_difference(1).divided_difference(2)
            X[3, 2, 4, 1]
            sage: a.divided_difference([4,1,3,2])
            X[1, 4, 2, 3]
            sage: b = X([4, 1, 3, 2])
            sage: b.divided_difference(1).divided_difference(2)
            X[1, 3, 4, 2]
            sage: b.divided_difference(1).divided_difference(2).divided_difference(3)
            X[1, 3, 2]
            sage: b.divided_difference(1).divided_difference(2).divided_difference(3).divided_difference(2)
            X[1]
            sage: b.divided_difference(1).divided_difference(2).divided_difference(3).divided_difference(3)
            0
            sage: b.divided_difference(1).divided_difference(2).divided_difference(1)
            0

        TESTS:

        Check that :trac:`23403` is fixed::

            sage: X = SchubertPolynomialRing(ZZ)
            sage: a = X([3,2,4,1])
            sage: a.divided_difference(2)
            0
            sage: a.divided_difference([3,2,1])
            0
            sage: a.divided_difference(0)
            Traceback (most recent call last):
            ...
            ValueError: cannot apply \delta_{0} to a (= X[3, 2, 4, 1])
        """
        if not self:  # if self is 0
            return self
        Perms = Permutations()
        if i in ZZ:
            if algorithm == "sage":
                if i <= 0:
                    raise ValueError(r"cannot apply \delta_{%s} to a (= %s)" %
                                     (i, self))
                # The operator `\delta_i` sends the Schubert
                # polynomial `X_\pi` (where `\pi` is a finitely supported
                # permutation of `\{1, 2, 3, \ldots\}`) to:
                # - the Schubert polynomial X_\sigma`, where `\sigma` is
                #   obtained from `\pi` by switching the values at `i` and `i+1`,
                #   if `i` is a descent of `\pi` (that is, `\pi(i) > \pi(i+1)`);
                # - `0` otherwise.
                # Notice that distinct `\pi`s lead to distinct `\sigma`s,
                # so we can use `_from_dict` here.
                res_dict = {}
                for pi, coeff in self:
                    pi = pi[:]
                    n = len(pi)
                    if n <= i:
                        continue
                    if pi[i - 1] < pi[i]:
                        continue
                    pi[i - 1], pi[i] = pi[i], pi[i - 1]
                    pi = Perms(pi).remove_extra_fixed_points()
                    res_dict[pi] = coeff
                return self.parent()._from_dict(res_dict)
            else:  # if algorithm == "symmetrica":
                return symmetrica.divdiff_schubert(i, self)
        elif i in Perms:
            if algorithm == "sage":
                i = Permutation(i)
                redw = i.reduced_word()
                res_dict = {}
                for pi, coeff in self:
                    next_pi = False
                    pi = pi[:]
                    n = len(pi)
                    for j in redw:
                        if n <= j:
                            next_pi = True
                            break
                        if pi[j - 1] < pi[j]:
                            next_pi = True
                            break
                        pi[j - 1], pi[j] = pi[j], pi[j - 1]
                    if next_pi:
                        continue
                    pi = Perms(pi).remove_extra_fixed_points()
                    res_dict[pi] = coeff
                return self.parent()._from_dict(res_dict)
            else:  # if algorithm == "symmetrica":
                return symmetrica.divdiff_perm_schubert(i, self)
        else:
            raise TypeError("i must either be an integer or permutation")
Пример #4
0
    def divided_difference(self, i, algorithm="sage"):
        r"""
        Return the ``i``-th divided difference operator, applied to
        ``self``.
        Here, ``i`` can be either a permutation or a positive integer.

        INPUT:
        
        - ``i`` -- permutation or positive integer

        - ``algorithm`` -- (default: ``'sage'``) either ``'sage'``
          or ``'symmetrica'``; this determines which software is
          called for the computation

        OUTPUT:

        The result of applying the ``i``-th divided difference
        operator to ``self``.
        
        If `i` is a positive integer, then the `i`-th divided
        difference operator `\delta_i` is the linear operator sending
        each polynomial `f = f(x_1, x_2, \ldots, x_n)` (in
        `n \geq i+1` variables) to the polynomial

        .. MATH::

            \frac{f - f_i}{x_i - x_{i+1}}, \qquad \text{ where }
            f_i = f(x_1, x_2, ..., x_{i-1}, x_{i+1}, x_i,
            x_{i+1}, ..., x_n) .

        If `\sigma` is a permutation in the `n`-th symmetric group,
        then the `\sigma`-th divided difference operator `\delta_\sigma`
        is the composition
        `\delta_{i_1} \delta_{i_2} \cdots \delta_{i_k}`, where
        `\sigma = s_{i_1} \circ s_{i_2} \circ \cdots \circ s_{i_k}` is
        any reduced expression for `\sigma` (the precise choice of
        reduced expression is immaterial).

        .. NOTE::

            The :meth:`expand` method results in a polynomial
            in `n` variables named ``x0, x1, ..., x(n-1)`` rather than
            `x_1, x_2, \ldots, x_n`.
            The variable named ``xi`` corresponds to `x_{i+1}`.
            Thus, ``self.divided_difference(i)`` involves the variables
            ``x(i-1)`` and ``xi`` getting switched (in the numerator).

        EXAMPLES::

            sage: X = SchubertPolynomialRing(ZZ)
            sage: a = X([3,2,1])
            sage: a.divided_difference(1)
            X[2, 3, 1]
            sage: a.divided_difference([3,2,1])
            X[1]
            sage: a.divided_difference(5)
            0

        Any divided difference of `0` is `0`::

            sage: X.zero().divided_difference(2)
            0

        This is compatible when a permutation is given as input::

            sage: a = X([3,2,4,1])
            sage: a.divided_difference([2,3,1])
            0
            sage: a.divided_difference(1).divided_difference(2)
            0

        ::

            sage: a = X([4,3,2,1])
            sage: a.divided_difference([2,3,1])
            X[3, 2, 4, 1]
            sage: a.divided_difference(1).divided_difference(2)
            X[3, 2, 4, 1]
            sage: a.divided_difference([4,1,3,2])
            X[1, 4, 2, 3]
            sage: b = X([4, 1, 3, 2])
            sage: b.divided_difference(1).divided_difference(2)
            X[1, 3, 4, 2]
            sage: b.divided_difference(1).divided_difference(2).divided_difference(3)
            X[1, 3, 2]
            sage: b.divided_difference(1).divided_difference(2).divided_difference(3).divided_difference(2)
            X[1]
            sage: b.divided_difference(1).divided_difference(2).divided_difference(3).divided_difference(3)
            0
            sage: b.divided_difference(1).divided_difference(2).divided_difference(1)
            0

        TESTS:

        Check that :trac:`23403` is fixed::

            sage: X = SchubertPolynomialRing(ZZ)
            sage: a = X([3,2,4,1])
            sage: a.divided_difference(2)
            0
            sage: a.divided_difference([3,2,1])
            0
            sage: a.divided_difference(0)
            Traceback (most recent call last):
            ...
            ValueError: cannot apply \delta_{0} to a (= X[3, 2, 4, 1])
        """
        if not self: # if self is 0
            return self
        Perms = Permutations()
        if i in ZZ:
            if algorithm == "sage":
                if i <= 0:
                    raise ValueError(r"cannot apply \delta_{%s} to a (= %s)" % (i, self))
                # The operator `\delta_i` sends the Schubert
                # polynomial `X_\pi` (where `\pi` is a finitely supported
                # permutation of `\{1, 2, 3, \ldots\}`) to:
                # - the Schubert polynomial X_\sigma`, where `\sigma` is
                #   obtained from `\pi` by switching the values at `i` and `i+1`,
                #   if `i` is a descent of `\pi` (that is, `\pi(i) > \pi(i+1)`);
                # - `0` otherwise.
                # Notice that distinct `\pi`s lead to distinct `\sigma`s,
                # so we can use `_from_dict` here.
                res_dict = {}
                for pi, coeff in self:
                    pi = pi[:]
                    n = len(pi)
                    if n <= i:
                        continue
                    if pi[i-1] < pi[i]:
                        continue
                    pi[i-1], pi[i] = pi[i], pi[i-1]
                    pi = Perms(pi).remove_extra_fixed_points()
                    res_dict[pi] = coeff
                return self.parent()._from_dict(res_dict)
            else: # if algorithm == "symmetrica":
                return symmetrica.divdiff_schubert(i, self)
        elif i in Perms:
            if algorithm == "sage":
                i = Permutation(i)
                redw = i.reduced_word()
                res_dict = {}
                for pi, coeff in self:
                    next_pi = False
                    pi = pi[:]
                    n = len(pi)
                    for j in redw:
                        if n <= j:
                            next_pi = True
                            break
                        if pi[j-1] < pi[j]:
                            next_pi = True
                            break
                        pi[j-1], pi[j] = pi[j], pi[j-1]
                    if next_pi:
                        continue
                    pi = Perms(pi).remove_extra_fixed_points()
                    res_dict[pi] = coeff
                return self.parent()._from_dict(res_dict)
            else: # if algorithm == "symmetrica":
                return symmetrica.divdiff_perm_schubert(i, self)
        else:
            raise TypeError("i must either be an integer or permutation")