Skip to content

Commit

Permalink
some details in permutations
Browse files Browse the repository at this point in the history
  • Loading branch information
fchapoton committed Sep 23, 2024
1 parent d1f99d1 commit 2980d5c
Showing 1 changed file with 53 additions and 62 deletions.
115 changes: 53 additions & 62 deletions src/sage/combinat/permutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,8 @@ def __classcall_private__(cls, l, algorithm='lex', sjt=None, check=True):
return RSK_inverse(P, Q, 'permutation')
# if it's a tuple or nonempty list of tuples, also assume cycle
# notation
elif isinstance(l, tuple) or \
(isinstance(l, list) and l and
all(isinstance(x, tuple) for x in l)):
elif isinstance(l, tuple) or (isinstance(l, list) and l and
all(isinstance(x, tuple) for x in l)):
if l and (isinstance(l[0], (int, Integer)) or len(l[0]) > 0):
if isinstance(l[0], tuple):
n = max(max(x) for x in l)
Expand Down Expand Up @@ -596,7 +595,7 @@ def __init__(self, parent, l, algorithm='lex', sjt=None, check=True):
raise ValueError("unsupported algorithm %s; expected 'lex' or 'sjt'"
% self._algorithm)

if check and len(l) > 0:
if check and l:
# Make a copy to sort later
lst = list(l)

Expand All @@ -615,14 +614,14 @@ def __init__(self, parent, l, algorithm='lex', sjt=None, check=True):
# Is the maximum element of the permutation the length of input,
# or is some integer missing ?
if int(lst[-1]) != len(lst):
raise ValueError("the permutation has length "+str(len(lst)) +
" but its maximal element is " +
str(int(lst[-1])) + ". Some element may be " +
raise ValueError(f"the permutation has length {len(lst)} " +
f"but its maximal element is {int(lst[-1])}" +
". Some element may be " +
"repeated, or an element is missing, but " +
"there is something wrong with its length.")

# Do the elements appear only once ?
previous = lst[0]-1
previous = lst[0] - 1

for i in lst:
if i == previous:
Expand Down Expand Up @@ -1653,7 +1652,7 @@ def _to_inversion_vector_orig(self):
[2, 3, 6, 4, 0, 2, 2, 1, 0]
"""
p = self._list
iv = [0]*len(p)
iv = [0] * len(p)
for i in range(len(p)):
for pj in p:
if pj > i+1:
Expand Down Expand Up @@ -1682,8 +1681,8 @@ def _to_inversion_vector_small(self):
"""
p = self._list
l = len(p)+1
iv = [0]*l
checked = [1]*l
iv = [0] * l
checked = [1] * l
for pi in reversed(p):
checked[pi] = 0
iv[pi] = sum(checked[pi:])
Expand Down Expand Up @@ -1738,8 +1737,8 @@ def merge_and_countv(ivA_A, ivB_B):
def base_case(L):
s = sorted(L)
d = {j: i for i, j in enumerate(s)}
iv = [0]*len(L)
checked = [1]*len(L)
iv = [0] * len(L)
checked = [1] * len(L)
for pi in reversed(L):
dpi = d[pi]
checked[dpi] = 0
Expand Down Expand Up @@ -1902,7 +1901,7 @@ def show(self, representation='cycles', orientation='landscape', **args):

L = line([r(1, 1)])
for i in range(len(p)):
L += line([r(i, 1.0), r(p[i]-1, 0)])
L += line([r(i, 1.0), r(p[i] - 1, 0)])
L += text(str(i), r(i, 1.05)) + text(str(i), r(p[i]-1, -.05))

return L.show(axes=False, **args)
Expand Down Expand Up @@ -2433,9 +2432,9 @@ def longest_increasing_subsequences(self):
for i in columns[0]:
D.add_edge(0, i) # 0 is source
for i in columns[-1]:
D.add_edge(i, n+1) # n+1 is sink
D.add_edge(i, n + 1) # n+1 is sink

return sorted([p[1:-1] for p in D.all_paths(0, n+1)], reverse=True)
return sorted([p[1:-1] for p in D.all_paths(0, n + 1)], reverse=True)

def longest_increasing_subsequences_number(self):
r"""
Expand Down Expand Up @@ -2659,7 +2658,7 @@ def foata_bijection(self) -> Permutation:
continue

a = M[-1]
M_prime = [0]*(k + 1)
M_prime = [0] * (k + 1)
# Locate the positions of the vertical lines.
if a > e:
index_list = [-1] + [i for i, val in enumerate(M) if val > e]
Expand Down Expand Up @@ -2711,7 +2710,7 @@ def foata_bijection_inverse(self) -> Permutation:
k = len(L)
if k <= 1:
continue
L_prime = [0]*(k)
L_prime = [0] * (k)
a = L[0]
# Locate the positions of the vertical lines.
if a > e:
Expand Down Expand Up @@ -2920,14 +2919,14 @@ def destandardize(self, weight, ordered_alphabet=None):
if not set(ides).issubset(set(partial)):
raise ValueError(f"Standardization with weight {weight} is not possible!")
if ordered_alphabet is None:
ordered_alphabet = list(range(1,len(weight)+1))
ordered_alphabet = list(range(1, len(weight)+1))
else:
if len(weight) > len(ordered_alphabet):
raise ValueError("Not enough letters in the alphabet are specified compared to the weight")
q = self.inverse()
s = [0]*len(self)
s = [0] * len(self)
for i in range(len(partial)-1):
for j in range(partial[i],partial[i+1]):
for j in range(partial[i], partial[i+1]):
s[q[j]-1] = ordered_alphabet[i]
from sage.combinat.words.word import Word
return Word(s)
Expand Down Expand Up @@ -2993,7 +2992,7 @@ def _to_lehmer_code_small(self) -> list:
p = self._list
l = len(p)
lehmer = []
checked = [1]*l
checked = [1] * l
for pi in p:
checked[pi-1] = 0
lehmer.append(sum(checked[:pi]))
Expand Down Expand Up @@ -3577,9 +3576,9 @@ def descent_polynomial(self):
EXAMPLES::
sage: Permutation([2,1,3]).descent_polynomial()
z1
z2
sage: Permutation([4,3,2,1]).descent_polynomial()
z1*z2^2*z3^3
z2*z3*z4
.. TODO::
Expand All @@ -3589,17 +3588,9 @@ def descent_polynomial(self):
(the descent monomial in their (7.23) is different).
"""
p = self
z = []
P = PolynomialRing(ZZ, len(p), 'z')
P = PolynomialRing(ZZ, len(p) + 1, 'z')
z = P.gens()
result = 1
pol = 1
for i in range(len(p)-1):
pol *= z[p[i]-1]
if p[i] > p[i+1]:
result *= pol

return result
return P.prod(z[p[i]] for i in range(len(p) - 1) if p[i] > p[i + 1])

##############
# Major Code #
Expand Down Expand Up @@ -3729,7 +3720,7 @@ def to_major_code(self, final_descent=False):
"""
p = self
n = len(p)
major_indices = [0]*(n+1)
major_indices = [0] * (n + 1)
smaller = p[:]
P = Permutations()
for i in range(n):
Expand Down Expand Up @@ -4232,7 +4223,7 @@ def permutohedron_succ(self, side='right'):
pp[i+1] = p[i]
succ.append(P(pp))
else:
advance = lambda perm: [i for i in range(1,n) if perm.index(i) < perm.index(i+1)]
advance = lambda perm: [i for i in range(1, n) if perm.index(i) < perm.index(i+1)]
for i in advance(p):
pp = p[:]
pp[p.index(i)] = i+1
Expand Down Expand Up @@ -4272,7 +4263,7 @@ def permutohedron_pred(self, side='right') -> list:
pp[d] = p[d - 1]
pred.append(P(pp))
else:
recoil = lambda perm: [i for i in range(1,n) if perm.index(i) > perm.index(i+1)]
recoil = lambda perm: [i for i in range(1, n) if perm.index(i) > perm.index(i+1)]
for i in recoil(p):
pp = p[:]
pp[p.index(i)] = i+1
Expand Down Expand Up @@ -4683,7 +4674,7 @@ def pattern_positions(self, patt) -> list:
if to_standard([p[z] for z in pos]) == patt]

@combinatorial_map(name='Simion-Schmidt map')
def simion_schmidt(self, avoid=[1,2,3]):
def simion_schmidt(self, avoid=[1, 2, 3]):
r"""
Implement the Simion-Schmidt map which sends an arbitrary permutation
to a pattern avoiding permutation, where the permutation pattern is one
Expand Down Expand Up @@ -4713,7 +4704,7 @@ def simion_schmidt(self, avoid=[1,2,3]):
targetPermutation = [self[0]]
extreme = self[0]
nonMinima = []
if avoid == [1,2,3] or avoid == [1,3,2]:
if avoid == [1, 2, 3] or avoid == [1, 3, 2]:
for i in range(1, len(list(self))):
if self[i] < extreme:
targetPermutation.append(self[i])
Expand All @@ -4722,9 +4713,9 @@ def simion_schmidt(self, avoid=[1,2,3]):
targetPermutation.append(None)
nonMinima.append(self[i])
nonMinima.sort()
if avoid == [1,3,2]:
if avoid == [1, 3, 2]:
nonMinima.reverse()
if avoid == [3,2,1] or avoid == [3,1,2]:
if avoid == [3, 2, 1] or avoid == [3, 1, 2]:
for i in range(1, len(list(self))):
if self[i] > extreme:
targetPermutation.append(self[i])
Expand All @@ -4733,7 +4724,7 @@ def simion_schmidt(self, avoid=[1,2,3]):
targetPermutation.append(None)
nonMinima.append(self[i])
nonMinima.sort()
if avoid == [3,2,1]:
if avoid == [3, 2, 1]:
nonMinima.reverse()

for i in range(1, len(list(self))):
Expand Down Expand Up @@ -5400,7 +5391,7 @@ def hyperoctahedral_double_coset_type(self):
n = len(self)
if n % 2 == 1:
raise ValueError("%s is a permutation of odd size and has no coset-type" % self)
S = PerfectMatchings(n)([(2*i+1,2*i+2) for i in range(n//2)])
S = PerfectMatchings(n)([(2*i+1, 2*i+2) for i in range(n//2)])
return S.loop_type(S.apply_permutation(self))

#####################
Expand Down Expand Up @@ -6019,13 +6010,13 @@ def __classcall_private__(cls, n=None, k=None, **kwargs):
else:
return StandardPermutations_n(n)
else:
return Permutations_nk(n,k)
return Permutations_nk(n, k)
else:
# In this case, we have that n is a list
# Because of UniqueRepresentation, we require the elements
# to be hashable
if len(set(n)) == len(n):
if list(n) == list(range(1, len(n)+1)):
if all(i == j for i, j in enumerate(n, start=1)):
if k is None:
return StandardPermutations_n(len(n))
else:
Expand All @@ -6034,7 +6025,7 @@ def __classcall_private__(cls, n=None, k=None, **kwargs):
if k is None:
return Permutations_set(n)
else:
return Permutations_setk(n,k)
return Permutations_setk(n, k)
else:
if k is None:
return Permutations_mset(n)
Expand Down Expand Up @@ -6110,7 +6101,7 @@ class options(GlobalOptions):
'description': "Specifies how the permutations should be printed",
'values': {'list': "the permutations are displayed in list notation"
" (aka 1-line notation)",
'cycle': "the permutations are displayed in cycle notation"
'cycle': "the permutations are displayed in cycle notation"
" (i. e., as products of disjoint cycles)",
'singleton': "the permutations are displayed in cycle notation"
" with singleton cycles shown as well",
Expand All @@ -6131,7 +6122,7 @@ class options(GlobalOptions):
'checker': lambda char: isinstance(char, str)}
generator_name = {'default': "s",
'description': "the letter used in latexing the reduced word",
'checker': lambda char: isinstance(char, str)}
'checker': lambda char: isinstance(char, str)}
mult = {'default': "l2r",
'description': "The multiplication of permutations",
'values': {'l2r': r"left to right: `(p_1 \cdot p_2)(x) = p_2(p_1(x))`",
Expand Down Expand Up @@ -6250,7 +6241,7 @@ def random_element(self):
sage: s in Permutations(3,2)
True
"""
return sample(range(1, self.n+1), self._k)
return sample(range(1, self.n + 1), self._k)


class Permutations_mset(Permutations):
Expand Down Expand Up @@ -7391,7 +7382,7 @@ def identity(self):
sage: Permutations(0).identity()
[]
"""
return self.element_class(self, range(1,self.n+1), check=False)
return self.element_class(self, range(1, self.n + 1), check=False)

one = identity

Expand Down Expand Up @@ -7449,7 +7440,7 @@ def random_element(self):
sage: s in Permutations(4)
True
"""
return self.element_class(self, sample(range(1, self.n+1), self.n),
return self.element_class(self, sample(range(1, self.n + 1), self.n),
check=False)

def cardinality(self):
Expand Down Expand Up @@ -7511,7 +7502,7 @@ def degrees(self):
sage: Permutations(7).degrees()
(2, 3, 4, 5, 6, 7)
"""
return tuple(Integer(i) for i in range(2, self.n+1))
return tuple(Integer(i) for i in range(2, self.n + 1))

def codegrees(self):
"""
Expand Down Expand Up @@ -7717,8 +7708,8 @@ def simple_reflection(self, i):
sage: P.simple_reflections()
Finite family {1: [2, 1, 3, 4], 2: [1, 3, 2, 4], 3: [1, 2, 4, 3]}
"""
g = list(range(1, self.n+1))
g[i-1] = i+1
g = list(range(1, self.n + 1))
g[i - 1] = i + 1
g[i] = i
return self.element_class(self, g, check=False)

Expand All @@ -7738,7 +7729,7 @@ def reflection_index_set(self):
sage: P.reflection_index_set()
((1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4))
"""
return tuple([tuple(c) for c in itertools.combinations(range(1, self.n+1), 2)])
return tuple([tuple(c) for c in itertools.combinations(range(1, self.n + 1), 2)])

def reflection(self, i):
r"""
Expand All @@ -7763,7 +7754,7 @@ def reflection(self, i):
(2, 4) [1, 4, 3, 2]
(3, 4) [1, 2, 4, 3]
"""
data = list(range(1, self.n+1))
data = list(range(1, self.n + 1))
data[i[0]-1] = i[1]
data[i[1]-1] = i[0]
return self.element_class(self, data, check=False)
Expand Down Expand Up @@ -8157,13 +8148,13 @@ def from_cycles(n, cycles, parent=None):
# check that the values are valid
if (k < 1) or (pk < 1):
raise ValueError("all elements should be strictly positive "
f"integers, but I found {min(k, pk)}")
f"integers, but I found {min(k, pk)}")
if (k > n) or (pk > n):
raise ValueError("you claimed that this is a permutation on "
f"1...{n}, but it contains {max(k, pk)}")
f"1...{n}, but it contains {max(k, pk)}")
if p[k - 1] is not None:
raise ValueError(f"the element {k} appears more than once"
" in the input")
" in the input")

p[k - 1] = pk
# values that are not in any cycle are fixed points of the permutation
Expand Down Expand Up @@ -8529,7 +8520,7 @@ def d(l):
if not self._d:
return one

l_ops = [1]*(self.n-1)
l_ops = [1] * (self.n-1)
for i in self._d:
l_ops[i] = 0
l = [one]
Expand Down Expand Up @@ -9186,7 +9177,7 @@ def to_standard(p, key=None):
We check against the naive method::
sage: def std(p):
....: s = [0]*len(p)
....: s = [0] * len(p)
....: c = p[:]
....: biggest = max(p) + 1
....: i = 1
Expand Down Expand Up @@ -9746,7 +9737,7 @@ def __iter__(self):
sage: Permutations(3, avoiding=[2,1]).list()
[[1, 2, 3]]
"""
yield self.element_class(self, range(1, self.n+1), check=False)
yield self.element_class(self, range(1, self.n + 1), check=False)

def cardinality(self):
"""
Expand Down

0 comments on commit 2980d5c

Please sign in to comment.