Skip to content

Commit

Permalink
Trac #27467: weak order of permutations broken
Browse files Browse the repository at this point in the history
From https://groups.google.com/forum/#!topic/sage-support/6kuvliWzi84:
{{{
sage: for w in Permutations(3):
....:     w, w.weak_covers()
....:
([1, 2, 3], [])
([1, 3, 2], [[1, 2, 3]])
([2, 1, 3], [[1, 2, 3]])
([2, 3, 1], [[3, 2, 1]])
([3, 1, 2], [[3, 2, 1]])
([3, 2, 1], [[3, 1, 2], [2, 3, 1]])

The fourth and fifth lines of the output are incorrect.
The correct values should be

([2, 3, 1], [[2, 1, 3]])
([3, 1, 2], [[1, 3, 2]])
}}}

This manifests also in creating the weak order poset:
{{{
sage: Permutations(3).weak_poset()
...
ValueError: Hasse diagram contains cycles
}}}

This is a left-vs-right issue and `Permutation` multiplication being a
little strange with respect to that. We also remove the multiplication
argument and convention effects from `has_*_descent`.

URL: https://trac.sagemath.org/27467
Reported by: tscrim
Ticket author(s): Travis Scrimshaw
Reviewer(s): Frédéric Chapoton, Darij Grinberg
  • Loading branch information
Release Manager committed Jun 11, 2019
2 parents 82e9b28 + fa0450e commit 8555a05
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 70 deletions.
6 changes: 2 additions & 4 deletions src/sage/algebras/yokonuma_hecke_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,10 +414,8 @@ def _product_by_basis_gen(self, m, i):
- (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"):
wi = w.apply_simple_reflection(i, side="right")
if not w.has_descent(i, side="right"):
return self.monomial((t, wi))

R = self.base_ring()
Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/dyck_word.py
Original file line number Diff line number Diff line change
Expand Up @@ -2015,7 +2015,7 @@ def to_312_avoiding_permutation(self):
for j in range(n):
for i in range(area[j]):
pi = pi.apply_simple_reflection(j - i)
return ~pi
return pi

@combinatorial_map(name='to non-crossing permutation')
def to_noncrossing_permutation(self):
Expand Down
170 changes: 105 additions & 65 deletions src/sage/combinat/permutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3012,7 +3012,7 @@ def descents(self, final_descent=False, side='right', positive=False,
Check that the original error of :trac:`23891` is fixed::
sage: Permutations(4)([1,4,3,2]).weak_covers()
[[1, 4, 2, 3], [1, 3, 4, 2]]
[[1, 3, 4, 2], [1, 4, 2, 3]]
"""
if index_set is None:
index_set = range(1, len(self))
Expand Down Expand Up @@ -6200,11 +6200,11 @@ def __init__(self, n, category=None):
"""
TESTS:
We skip the reduced word method because it does not respect the
ordering for multiplication::
We skip the descent and reduced word methods because they do
not respect the ordering for multiplication::
sage: SP = Permutations(3)
sage: TestSuite(SP).run(skip='_test_reduced_word')
sage: TestSuite(SP).run(skip=['_test_reduced_word', '_test_has_descent'])
sage: SP.options.mult='r2l'
sage: TestSuite(SP).run()
Expand Down Expand Up @@ -6710,27 +6710,10 @@ def has_left_descent(self, i, mult=None):
A *left descent* of a permutation `\pi \in S_n` means an index
`i \in \{ 1, 2, \ldots, n-1 \}` such that
`s_i \circ \pi` has smaller length than `\pi`. Here, `\circ`
denotes the multiplication of `S_n`. How it is defined depends
on the ``mult`` variable in
:meth:`Permutations.options`. If this variable is set
to ``'l2r'``, then the multiplication is defined by the rule
`(\alpha \beta) (x) = \beta( \alpha (x) )` for `\alpha,
\beta \in S_n` and `x \in \{ 1, 2, \ldots, n \}`; then, a left
descent of `\pi` is an index `i \in \{ 1, 2, \ldots, n-1 \}`
satisfying `\pi(i) > \pi(i+1)`. If this variable is set
to ``'r2l'``, then the multiplication is defined by the rule
`(\alpha \beta) (x) = \alpha( \beta (x) )` for `\alpha,
\beta \in S_n` and `x \in \{ 1, 2, \ldots, n \}`; then, a left
`s_i \circ \pi` has smaller length than `\pi`. Thus, a left
descent of `\pi` is an index `i \in \{ 1, 2, \ldots, n-1 \}`
satisfying `\pi^{-1}(i) > \pi^{-1}(i+1)`.
The optional parameter ``mult`` can be set to ``'l2r'`` or
``'r2l'``; if so done, it is used instead of the ``mult``
variable in :meth:`Permutations.options`. Anyone using
this method in a non-interactive environment is encouraged to
do so in order to have code behave reliably.
.. WARNING::
The methods :meth:`descents` and :meth:`idescents` behave
Expand All @@ -6740,55 +6723,51 @@ def has_left_descent(self, i, mult=None):
.. WARNING::
The optional input ``mult`` might disappear once :trac:`14881`
is fixed.
This ignores the multiplication convention in order
to be consistent with other Coxeter operations in
permutations (e.g., computing :meth:`reduced_word`).
EXAMPLES::
sage: P = Permutations(4)
sage: x = P([3, 2, 4, 1])
sage: x.descents()
[1, 3]
sage: (~x).descents()
[1, 2]
sage: [i for i in P.index_set() if x.has_left_descent(i)]
[1, 3]
sage: [i for i in P.index_set() if x.has_left_descent(i, mult="l2r")]
[1, 3]
sage: [i for i in P.index_set() if x.has_left_descent(i, mult="r2l")]
[1, 2]
TESTS::
sage: P = Permutations(4)
sage: x = P([3, 2, 4, 1])
sage: x.has_left_descent(2, mult='l2r')
doctest:warning
...
DeprecationWarning: The mult option is deprecated and ignored.
See https://trac.sagemath.org/27467 for details.
True
sage: x.has_left_descent(2, mult='r2l')
True
"""
if mult is None:
mult = self.parent().options.mult
if mult != 'l2r':
self = self.inverse()
return self[i-1] > self[i]
if mult is not None:
from sage.misc.superseded import deprecation
deprecation(27467, "The mult option is deprecated and ignored.")
for val in self._list:
if val == i:
return False
if val == i + 1:
return True

def has_right_descent(self, i, mult=None):
r"""
Check if ``i`` is a right descent of ``self``.
A *right descent* of a permutation `\pi \in S_n` means an index
`i \in \{ 1, 2, \ldots, n-1 \}` such that
`\pi \circ s_i` has smaller length than `\pi`. Here, `\circ`
denotes the multiplication of `S_n`. How it is defined depends
on the ``mult`` variable in
:meth:`Permutations.options`. If this variable is set
to ``'l2r'``, then the multiplication is defined by the rule
`(\alpha \beta) (x) = \beta( \alpha (x) )` for `\alpha,
\beta \in S_n` and `x \in \{ 1, 2, \ldots, n \}`; then, a right
descent of `\pi` is an index `i \in \{ 1, 2, \ldots, n-1 \}`
satisfying `\pi^{-1}(i) > \pi^{-1}(i+1)`. If this variable is
set to ``'r2l'``, then the multiplication is defined by the
rule `(\alpha \beta) (x) = \alpha( \beta (x) )` for `\alpha,
\beta \in S_n` and `x \in \{ 1, 2, \ldots, n \}`; then, a right
`\pi \circ s_i` has smaller length than `\pi`. Thus, a right
descent of `\pi` is an index `i \in \{ 1, 2, \ldots, n-1 \}`
satisfying `\pi(i) > \pi(i+1)`.
The optional parameter ``mult`` can be set to ``'l2r'`` or
``'r2l'``; if so done, it is used instead of the ``mult``
variable in :meth:`Permutations.options`. Anyone using
this method in a non-interactive environment is encouraged to
do so in order to have code behave reliably.
.. WARNING::
The methods :meth:`descents` and :meth:`idescents` behave
Expand All @@ -6798,26 +6777,35 @@ def has_right_descent(self, i, mult=None):
.. WARNING::
The optional input ``mult`` might disappear once :trac:`14881`
is fixed.
This ignores the multiplication convention in order
to be consistent with other Coxeter operations in
permutations (e.g., computing :meth:`reduced_word`).
EXAMPLES::
sage: P = Permutations(4)
sage: x = P([3, 2, 4, 1])
sage: (~x).descents()
[1, 2]
sage: x.descents()
[1, 3]
sage: [i for i in P.index_set() if x.has_right_descent(i)]
[1, 2]
sage: [i for i in P.index_set() if x.has_right_descent(i, mult="l2r")]
[1, 2]
sage: [i for i in P.index_set() if x.has_right_descent(i, mult="r2l")]
[1, 3]
TESTS::
sage: P = Permutations(4)
sage: x = P([3, 2, 4, 1])
sage: x.has_right_descent(3, mult='l2r')
doctest:warning
...
DeprecationWarning: The mult option is deprecated and ignored.
See https://trac.sagemath.org/27467 for details.
True
sage: x.has_right_descent(3, mult='r2l')
True
"""
if mult is None:
mult = self.parent().options.mult
if mult != 'r2l':
self = self.inverse()
if mult is not None:
from sage.misc.superseded import deprecation
deprecation(27467, "The mult option is deprecated and ignored.")
return self[i-1] > self[i]

def __mul__(self, other):
Expand Down Expand Up @@ -6887,6 +6875,58 @@ def inverse(self):

__invert__ = inverse

def apply_simple_reflection_left(self, i):
r"""
Return ``self`` multiplied by the simple reflection ``s[i]``
on the left.
This acts by switching the entries in positions `i` and `i+1`.
.. WARNING::
This ignores the multiplication convention in order
to be consistent with other Coxeter operations in
permutations (e.g., computing :meth:`reduced_word`).
EXAMPLES::
sage: W = Permutations(3)
sage: w = W([2,3,1])
sage: w.apply_simple_reflection_left(1)
[1, 3, 2]
sage: w.apply_simple_reflection_left(2)
[3, 2, 1]
"""
s = self.parent().simple_reflections()[i]
p = right_action_same_n(self._list, s._list)
return self.__class__(self.parent(), p)

def apply_simple_reflection_right(self, i):
r"""
Return ``self`` multiplied by the simple reflection ``s[i]``
on the right.
This acts by switching the entries `i` and `i+1`.
.. WARNING::
This ignores the multiplication convention in order
to be consistent with other Coxeter operations in
permutations (e.g., computing :meth:`reduced_word`).
EXAMPLES::
sage: W = Permutations(3)
sage: w = W([2,3,1])
sage: w.apply_simple_reflection_right(1)
[3, 2, 1]
sage: w.apply_simple_reflection_right(2)
[2, 1, 3]
"""
s = self.parent().simple_reflections()[i]
p = left_action_same_n(self._list, s._list)
return self.__class__(self.parent(), p)

#############################
# Constructing Permutations #
#############################
Expand Down

0 comments on commit 8555a05

Please sign in to comment.