Skip to content

Commit 9144e18

Browse files
author
Release Manager
committed
sagemathgh-39385: use the faster binomial in combinat as the binomial method of integers is way faster than the general purpose binomial from `arith.misc` also a few other minor code changes ### 📝 Checklist - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. URL: sagemath#39385 Reported by: Frédéric Chapoton Reviewer(s): Frédéric Chapoton, Vincent Macri
2 parents 4187178 + db52fb0 commit 9144e18

File tree

9 files changed

+139
-151
lines changed

9 files changed

+139
-151
lines changed

src/sage/combinat/affine_permutation.py

Lines changed: 66 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
# ****************************************************************************
1414
from itertools import repeat
1515

16-
from sage.arith.misc import binomial
1716
from sage.categories.affine_weyl_groups import AffineWeylGroups
1817
from sage.combinat.composition import Composition
1918
from sage.combinat.partition import Partition
@@ -23,7 +22,7 @@
2322
from sage.misc.lazy_import import lazy_import
2423
from sage.misc.misc_c import prod
2524
from sage.misc.prandom import randint
26-
from sage.rings.integer_ring import ZZ
25+
from sage.rings.integer import Integer
2726
from sage.structure.list_clone import ClonableArray
2827
from sage.structure.parent import Parent
2928
from sage.structure.unique_representation import UniqueRepresentation
@@ -76,14 +75,14 @@ def __init__(self, parent, lst, check=True):
7675
Type A affine permutation with window [1, 2, 3, 4]
7776
"""
7877
if check:
79-
lst = [ZZ(val) for val in lst]
78+
lst = [Integer(val) for val in lst]
8079
self.k = parent.k
8180
self.n = self.k + 1
82-
#This N doesn't matter for type A, but comes up in all other types.
81+
# This N doesn't matter for type A, but comes up in all other types.
8382
if parent.cartan_type()[0] == 'A':
8483
self.N = self.n
8584
elif parent.cartan_type()[0] in ['B', 'C', 'D']:
86-
self.N = 2*self.k + 1
85+
self.N = 2 * self.k + 1
8786
elif parent.cartan_type()[0] == 'G':
8887
self.N = 6
8988
else:
@@ -245,7 +244,7 @@ def is_i_grassmannian(self, i=0, side='right') -> bool:
245244
"""
246245
return self == self.parent().one() or self.descents(side) == [i]
247246

248-
def index_set(self):
247+
def index_set(self) -> tuple:
249248
r"""
250249
Index set of the affine permutation group.
251250
@@ -255,7 +254,7 @@ def index_set(self):
255254
sage: A.index_set()
256255
(0, 1, 2, 3, 4, 5, 6, 7)
257256
"""
258-
return tuple(range(self.k+1))
257+
return tuple(range(self.k + 1))
259258

260259
def lower_covers(self, side='right'):
261260
r"""
@@ -305,7 +304,7 @@ def reduced_word(self):
305304
sage: p.reduced_word()
306305
[0, 7, 4, 1, 0, 7, 5, 4, 2, 1]
307306
"""
308-
#This is about 25% faster than the default algorithm.
307+
# This is about 25% faster than the default algorithm.
309308
x = self
310309
i = 0
311310
word = []
@@ -410,10 +409,10 @@ def grassmannian_quotient(self, i=0, side='right'):
410409

411410

412411
class AffinePermutationTypeA(AffinePermutation):
413-
#----------------------
414-
#Type-specific methods.
415-
#(Methods existing in all types, but with type-specific definition.)
416-
#----------------------
412+
# ----------------------
413+
# Type-specific methods.
414+
# (Methods existing in all types, but with type-specific definition.)
415+
# ----------------------
417416
def check(self):
418417
r"""
419418
Check that ``self`` is an affine permutation.
@@ -440,13 +439,14 @@ def check(self):
440439
if not self:
441440
return
442441
k = self.parent().k
443-
#Type A.
442+
# Type A
444443
if len(self) != k + 1:
445-
raise ValueError("length of list must be k+1="+str(k+1))
446-
if binomial(k+2,2) != sum(self):
447-
raise ValueError("window does not sum to " + str(binomial((k+2),2)))
448-
l = sorted([i % (k+1) for i in self])
449-
if l != list(range(k+1)):
444+
raise ValueError(f"length of list must be k+1={k + 1}")
445+
sigma = (k + 2).binomial(2)
446+
if sigma != sum(self):
447+
raise ValueError(f"window does not sum to {sigma}")
448+
l = sorted(i % (k + 1) for i in self)
449+
if any(i != j for i, j in enumerate(l)):
450450
raise ValueError("entries must have distinct residues")
451451

452452
def value(self, i, base_window=False):
@@ -510,11 +510,11 @@ def apply_simple_reflection_right(self, i):
510510
Type A affine permutation with window [3, -1, 6, 0, 5, 4, 10, 9]
511511
"""
512512
j = i % (self.k+1)
513-
#Cloning is currently kinda broken, in that caches don't clear which
514-
#leads to strangeness with the cloned object.
515-
#The clone approach is quite a bit (2x) faster, though, so this should
516-
#switch once the caching situation is fixed.
517-
#with self.clone(check=False) as l:
513+
# Cloning is currently kinda broken, in that caches don't clear which
514+
# leads to strangeness with the cloned object.
515+
# The clone approach is quite a bit (2x) faster, though, so this should
516+
# switch once the caching situation is fixed.
517+
# with self.clone(check=False) as l:
518518
l = self[:]
519519
if j == 0:
520520
a = l[0]
@@ -524,7 +524,6 @@ def apply_simple_reflection_right(self, i):
524524
a = l[j-1]
525525
l[j-1] = l[j]
526526
l[j] = a
527-
#return l
528527
return type(self)(self.parent(), l, check=False)
529528

530529
def apply_simple_reflection_left(self, i):
@@ -539,18 +538,18 @@ def apply_simple_reflection_left(self, i):
539538
sage: p.apply_simple_reflection_left(11)
540539
Type A affine permutation with window [4, -1, 0, 6, 5, 3, 10, 9]
541540
"""
542-
#Here are a couple other methods we tried out, but turned out
543-
#to be slower than the current implementation.
544-
#1) This one was very bad:
545-
# return self.inverse().apply_simple_reflection_right(i).inverse()
546-
#2) Also bad, though not quite so bad:
547-
# return (self.parent().simple_reflection(i))*self
548-
i = i % (self.k+1)
549-
#Cloning is currently kinda broken, in that caches don't clear which
550-
#leads to strangeness with the cloned object.
551-
#The clone approach is quite a bit faster, though, so this should switch
552-
#once the caching situation is fixed.
553-
#with self.clone(check=False) as l:
541+
# Here are a couple other methods we tried out, but turned out
542+
# to be slower than the current implementation.
543+
# 1) This one was very bad:
544+
# return self.inverse().apply_simple_reflection_right(i).inverse()
545+
# 2) Also bad, though not quite so bad:
546+
# return (self.parent().simple_reflection(i))*self
547+
i = i % (self.k + 1)
548+
# Cloning is currently kinda broken, in that caches don't clear which
549+
# leads to strangeness with the cloned object.
550+
# The clone approach is quite a bit faster, though,
551+
# so this should switch once the caching situation is fixed.
552+
# with self.clone(check=False) as l:
554553
l = []
555554
if i != self.k:
556555
for m in range(self.k + 1):
@@ -627,10 +626,10 @@ def to_type_a(self):
627626
"""
628627
return self
629628

630-
#----------------------
631-
#Type-A-specific methods.
632-
#Only available in Type A.
633-
#----------------------
629+
# ----------------------
630+
# Type-A-specific methods.
631+
# Only available in Type A.
632+
# ----------------------
634633

635634
def flip_automorphism(self):
636635
r"""
@@ -699,7 +698,7 @@ def maximal_cyclic_factor(self, typ='decreasing', side='right', verbose=False):
699698
else:
700699
descents = self.descents(side='left')
701700
side = 'left'
702-
#for now, assume side is 'right')
701+
# for now, assume side is 'right')
703702
best_T = []
704703
for i in descents:
705704
y = self.clone().apply_simple_reflection(i,side)
@@ -834,18 +833,18 @@ def to_lehmer_code(self, typ='decreasing', side='right'):
834833
"""
835834
code = [0 for i in range(self.k+1)]
836835
if typ[0] == 'i' and side[0] == 'r':
837-
#Find number of positions to the right of position i with smaller
838-
#value than the number in position i.
836+
# Find number of positions to the right of position i with smaller
837+
# value than the number in position i.
839838
for i in range(self.k+1):
840839
a = self(i)
841840
for j in range(i+1, i+self.k+1):
842841
b = self(j)
843842
if b < a:
844843
code[i] += (a-b) // (self.k+1) + 1
845844
elif typ[0] == 'd' and side[0] == 'r':
846-
#Find number of positions to the left of position i with larger
847-
#value than the number in position i. Then cyclically shift
848-
#the resulting vector.
845+
# Find number of positions to the left of position i with larger
846+
# value than the number in position i. Then cyclically shift
847+
# the resulting vector.
849848
for i in range(self.k+1):
850849
a = self(i)
851850
for j in range(i-self.k, i):
@@ -855,18 +854,18 @@ def to_lehmer_code(self, typ='decreasing', side='right'):
855854
if a < b:
856855
code[i-1] += ((b-a)//(self.k+1)+1)
857856
elif typ[0] == 'i' and side[0] == 'l':
858-
#Find number of positions to the right of i smaller than i, then
859-
#cyclically shift the resulting vector.
857+
# Find number of positions to the right of i smaller than i, then
858+
# cyclically shift the resulting vector.
860859
for i in range(self.k+1):
861860
pos = self.position(i)
862861
for j in range(pos+1, pos+self.k+1):
863862
b = self(j)
864-
#A small rotation is necessary for the reduced word from
865-
#the lehmer code to match the element.
863+
# A small rotation is necessary for the reduced word from
864+
# the lehmer code to match the element.
866865
if b < i:
867866
code[i-1] += (i-b) // (self.k+1) + 1
868867
elif typ[0] == 'd' and side[0] == 'l':
869-
#Find number of positions to the left of i larger than i.
868+
# Find number of positions to the left of i larger than i.
870869
for i in range(self.k+1):
871870
pos = self.position(i)
872871
for j in range(pos-self.k, pos):
@@ -1103,7 +1102,7 @@ def value(self, i):
11031102
11041103
sage: C = AffinePermutationGroup(['C',4,1])
11051104
sage: x = C.one()
1106-
sage: [x.value(i) for i in range(-10,10)] == list(range(-10,10))
1105+
sage: all(x.value(i) == i for i in range(-10,10))
11071106
True
11081107
"""
11091108
N = 2*self.k + 1
@@ -1124,7 +1123,7 @@ def position(self, i):
11241123
11251124
sage: C = AffinePermutationGroup(['C',4,1])
11261125
sage: x = C.one()
1127-
sage: [x.position(i) for i in range(-10,10)] == list(range(-10,10))
1126+
sage: all(x.position(i) == i for i in range(-10,10))
11281127
True
11291128
"""
11301129
N = 2*self.k + 1
@@ -2001,9 +2000,9 @@ class AffinePermutationGroupGeneric(UniqueRepresentation, Parent):
20012000
methods for the specific affine permutation groups.
20022001
"""
20032002

2004-
#----------------------
2005-
#Type-free methods.
2006-
#----------------------
2003+
# ----------------------
2004+
# Type-free methods.
2005+
# ----------------------
20072006

20082007
def __init__(self, cartan_type):
20092008
r"""
@@ -2014,13 +2013,13 @@ def __init__(self, cartan_type):
20142013
"""
20152014
Parent.__init__(self, category=AffineWeylGroups())
20162015
ct = CartanType(cartan_type)
2017-
self.k = ct.n
2016+
self.k = Integer(ct.n)
20182017
self.n = ct.rank()
2019-
#This N doesn't matter for type A, but comes up in all other types.
2018+
# This N doesn't matter for type A, but comes up in all other types.
20202019
if ct.letter == 'A':
20212020
self.N = self.k + 1
20222021
elif ct.letter == 'B' or ct.letter == 'C' or ct.letter == 'D':
2023-
self.N = 2*self.k + 1
2022+
self.N = 2 * self.k + 1
20242023
elif ct.letter == 'G':
20252024
self.N = 6
20262025
self._cartan_type = ct
@@ -2034,14 +2033,14 @@ def _element_constructor_(self, *args, **keywords):
20342033
"""
20352034
return self.element_class(self, *args, **keywords)
20362035

2037-
def _repr_(self):
2036+
def _repr_(self) -> str:
20382037
r"""
20392038
TESTS::
20402039
20412040
sage: AffinePermutationGroup(['A',7,1])
20422041
The group of affine permutations of type ['A', 7, 1]
20432042
"""
2044-
return "The group of affine permutations of type "+str(self.cartan_type())
2043+
return "The group of affine permutations of type " + str(self.cartan_type())
20452044

20462045
def _test_enumeration(self, n=4, **options):
20472046
r"""
@@ -2242,12 +2241,12 @@ def one(self):
22422241
True
22432242
sage: TestSuite(A).run()
22442243
"""
2245-
return self(list(range(1, self.k + 2)))
2244+
return self(range(1, self.k + 2))
22462245

2247-
#------------------------
2248-
#Type-unique methods.
2249-
#(Methods which do not exist in all types.)
2250-
#------------------------
2246+
# ------------------------
2247+
# Type-unique methods.
2248+
# (Methods which do not exist in all types.)
2249+
# ------------------------
22512250
def from_lehmer_code(self, C, typ='decreasing', side='right'):
22522251
r"""
22532252
Return the affine permutation with the supplied Lehmer code (a weak
@@ -2353,7 +2352,7 @@ def one(self):
23532352
True
23542353
sage: TestSuite(C).run()
23552354
"""
2356-
return self(list(range(1, self.k + 1)))
2355+
return self(range(1, self.k + 1))
23572356

23582357
Element = AffinePermutationTypeC
23592358

src/sage/combinat/baxter_permutations.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
"""
22
Baxter permutations
33
"""
4-
5-
from sage.structure.unique_representation import UniqueRepresentation
6-
from sage.structure.parent import Parent
7-
from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
84
from sage.combinat.permutation import Permutations
9-
5+
from sage.rings.integer import Integer
106
from sage.rings.integer_ring import ZZ
7+
from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
8+
from sage.structure.parent import Parent
9+
from sage.structure.unique_representation import UniqueRepresentation
1110

1211

1312
class BaxterPermutations(UniqueRepresentation, Parent):
@@ -79,11 +78,11 @@ def __init__(self, n):
7978
Baxter permutations of size 5
8079
"""
8180
self.element_class = Permutations(n).element_class
82-
self._n = ZZ(n)
81+
self._n = Integer(n)
8382
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
8483
super().__init__(category=FiniteEnumeratedSets())
8584

86-
def _repr_(self):
85+
def _repr_(self) -> str:
8786
"""
8887
Return a string representation of ``self``.
8988
@@ -93,9 +92,9 @@ def _repr_(self):
9392
sage: BaxterPermutations_size(5)
9493
Baxter permutations of size 5
9594
"""
96-
return "Baxter permutations of size %s" % self._n
95+
return f"Baxter permutations of size {self._n}"
9796

98-
def __contains__(self, x):
97+
def __contains__(self, x) -> bool:
9998
r"""
10099
Return ``True`` if and only if ``x`` is a Baxter permutation of
101100
size ``self._n``.
@@ -228,12 +227,11 @@ def cardinality(self):
228227
Integer Ring
229228
"""
230229
if self._n == 0:
231-
return 1
232-
from sage.arith.misc import binomial
233-
return sum((binomial(self._n + 1, k) *
234-
binomial(self._n + 1, k + 1) *
235-
binomial(self._n + 1, k + 2)) //
236-
((self._n + 1) * binomial(self._n + 1, 2))
230+
return ZZ.one()
231+
n = self._n + 1
232+
return sum((n.binomial(k) *
233+
n.binomial(k + 1) *
234+
n.binomial(k + 2)) // (n * n.binomial(2))
237235
for k in range(self._n))
238236

239237

0 commit comments

Comments
 (0)