Skip to content

Commit 121cebf

Browse files
authored
Merge pull request Macaulay2#3806 from seangrate/Permutations
Package update: Permutations v1.1
2 parents cbb4d09 + 2d885ab commit 121cebf

File tree

12 files changed

+2623
-2016
lines changed

12 files changed

+2623
-2016
lines changed

M2/Macaulay2/packages/Permutations.m2

Lines changed: 26 additions & 313 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
newPackage(
22
"Permutations",
33
AuxiliaryFiles => true,
4-
Version => "1.0",
5-
Date => "August 7, 2024",
4+
Version => "1.1",
5+
Date => "May 13, 2025",
66
Keywords => {"Combinatorics"},
77
Authors => {
88
{Name => "Sean Grate",
99
Email => "[email protected]",
1010
HomePage => "https://seangrate.com/"}
1111
},
12-
Headline => "functions for working with permutations"
13-
)
12+
Headline => "functions for working with permutations",
13+
PackageExports => {"Posets"})
1414

1515
export {
1616
-- types
@@ -31,340 +31,53 @@ export {
3131
"isVexillary",
3232
"isCartwrightSturmfels",
3333
"isCDG",
34+
"isSeparable",
3435
"foataBijection",
3536
"ord",
3637
"isEven",
3738
"isOdd",
3839
"isDerangement",
3940
"fixedPoints",
4041
"inversions",
42+
"randomPermutation",
43+
"reducedWords",
44+
"weakBruhatOrder",
45+
"strongBruhatOrder",
46+
"symmetricGroupPoset",
47+
"transposition",
4148
-- symbols
42-
"Weak"
49+
"Weak",
50+
"Side"
4351
}
4452

53+
4554
-----------------------------------------------------------------------------
4655
-- **CODE** --
4756
-----------------------------------------------------------------------------
48-
------------------------------------
49-
-- Local utilities
50-
------------------------------------
51-
to1Index := w -> (w / (i -> i+1))
52-
to0Index := w -> (w / (i -> i-1))
53-
54-
------------------------------------
55-
-- Permutation type declarations and basic constructors
56-
------------------------------------
57-
Permutation = new Type of VisibleList
58-
Permutation.synonym = "permutation"
59-
60-
new Permutation from VisibleList := (typeofPermutation,w) -> w
61-
62-
permutation = method()
63-
permutation VisibleList := Permutation => w -> new Permutation from w
64-
65-
isWellDefined Permutation := Boolean => w -> (
66-
wList := toList w;
67-
((sort wList) == toList(1..#wList)) and not (#wList == 0)
68-
)
69-
70-
------------------------------------
71-
-- Permutation string representations
72-
------------------------------------
73-
expression Permutation := w -> expression toList w
74-
toString Permutation := w -> toString expression toList w
75-
tex Permutation := w -> tex expression toSequence w
76-
html Permutation := w -> html expression toList w
77-
78-
------------------------------------
79-
-- Indexing permutations as lists
80-
------------------------------------
81-
Permutation _ ZZ := ZZ => (w,n) -> ((toList w)_(n-1))
82-
Permutation _ List := List => (w,l) -> ((toList w)_l)
83-
Permutation _ Sequence := List => (w,s) -> ((toList w)_(toList s))
84-
85-
------------------------------------
86-
-- Change which symmetric group S_n to view a permutation as an element of
87-
------------------------------------
88-
trim Permutation := Permutation => o -> w -> (
89-
w = w_(select(#w, i -> w_{i ..< #w} != toList(i+1 .. #w)));
90-
if #w == 0 then permutation {1} else permutation w
91-
)
92-
93-
extend (Permutation, ZZ) := Permutation => o -> (w,n) -> (
94-
if n < #w then error(toString w | " is a permutation on more than " | toString n | " letters.");
95-
permutation(toList(w) | toList(#w+1..n))
96-
)
97-
extend (Permutation, Permutation) := Sequence => o -> (w,v) -> (
98-
n := max(#w, #v);
99-
(extend(w,n), extend(v,n))
100-
)
101-
102-
------------------------------------
103-
-- Basic permutation operations
104-
------------------------------------
105-
Permutation == Permutation := Boolean => (w, v) -> (
106-
(w, v) = extend(w,v);
107-
toList(w) == toList(v)
108-
)
109-
Permutation * Permutation := Permutation => (w, v) -> (
110-
(w,v) = extend(w,v);
111-
trim permutation w_(to0Index toList v)
112-
)
113-
-- power implementation modified from Mahrud's in https://github.com/Macaulay2/M2/issues/2581
114-
Permutation ^ ZZ := Permutation => (w, n) -> fold(if n < 0 then (-n):(permutation to1Index inversePermutation to0Index toList w) else n:w,
115-
permutation toList (1 .. #w),
116-
(w, v) -> w*v)
117-
118-
------------------------------------
119-
-- Matrix representation of a permutation
120-
------------------------------------
121-
-- some people prefer the transpose of this
122-
matrix Permutation := Matrix => o -> w -> (
123-
id_(ZZ^(#w))_(to0Index toList w)
124-
)
125-
126-
------------------------------------
127-
-- Group actions
128-
------------------------------------
129-
Permutation * VisibleList := VisibleList => (w, l) -> (
130-
if #(trim w) > #l then error(toString w | " permutes more than " | toString #l | " elements.")
131-
else l_(to0Index toList extend(w, #l))
132-
)
133-
VisibleList _ Permutation := VisibleList => (l, w) -> (w*l)
134-
135-
-- group action on a matrix permutes the rows/columns of the matrix
136-
Permutation * Matrix := Matrix => (w, M) -> (
137-
m := numRows M;
138-
if #(trim w) > m then error(toString w | " permutes more than " | toString m | " elements.")
139-
else (matrix extend(w, m)) * M
140-
)
141-
Matrix _ Permutation := Matrix => (M, w) -> (w*M)
142-
Matrix * Permutation := Matrix => (M, w) -> (transpose(w*(transpose M)))
143-
Matrix ^ Permutation := Matrix => (M, w) -> (M*w)
144-
145-
------------------------------------
146-
-- Cycle decomposition of a permutation
147-
------------------------------------
148-
-- every permutation can be written as a product of disjoint cycles (in cycle notation)
149-
cycleDecomposition = method()
150-
cycleDecomposition Permutation := List => w -> (
151-
w = to0Index toList w;
152-
cycles := {};
153-
unvisited := toList(0 ..< #w);
154-
while #unvisited != 0 do (
155-
startIdx := unvisited#0;
156-
visited := {startIdx};
157-
nextIdx := w#startIdx;
158-
while nextIdx != startIdx do (
159-
visited = append(visited, nextIdx);
160-
nextIdx = w#nextIdx;
161-
);
162-
cycles = append(cycles, visited);
163-
for idx in visited do unvisited = delete(idx, unvisited);
164-
);
165-
cycles = cycles / to1Index / toSequence;
166-
-- put decomposition into its standard or canonical representation (see https://en.wikipedia.org/wiki/Permutation#canonical_cycle_notation)
167-
-- a permutation's cycle decomposition is "canonical" or "standard" if
168-
-- 1. each cycle lists the largest element first and
169-
-- 2. the cycles are sorted by their first element in increasing order
170-
sortedCycles := for cycle in cycles list toSequence rotate(maxPosition cycle, toList cycle);
171-
sort sortedCycles
172-
)
173-
174-
cycleType = method()
175-
cycleType Permutation := Sequence => w -> (
176-
toSequence rsort for cycle in cycleDecomposition w list #cycle
177-
)
178-
179-
------------------------------------
180-
-- Ascents, descents, runs, exceedances, and records
181-
-- NOTE: All return the 1-indexed results for consistency with the permutation notation
182-
------------------------------------
183-
ascents = method()
184-
ascents Permutation := List => w -> (
185-
for i in 1 ..< #w list if w_i < w_(i+1) then i else continue
186-
)
187-
188-
descents = method()
189-
descents Permutation := List => w -> (
190-
for i in 1 ..< #w list if w_i > w_(i+1) then i else continue
191-
)
192-
193-
ascendingRuns = method()
194-
ascendingRuns Permutation := List => w -> (
195-
-- inspired from the SageMath implementation
196-
-- https://github.com/sagemath/sage/blob/develop/src/sage/combinat/permutation.py
197-
if #w == 1 then allRuns := {toSequence w}
198-
else (
199-
allRuns = {};
200-
currentRun := {w#0};
201-
for wi in w_(toList(1 ..< #w)) do (
202-
if wi > last currentRun then currentRun = append(currentRun, wi)
203-
else (
204-
allRuns = append(allRuns, toSequence currentRun);
205-
currentRun = {wi};
206-
);
207-
);
208-
allRuns = append(allRuns, toSequence currentRun);
209-
);
210-
allRuns
211-
)
212-
213-
descendingRuns = method()
214-
descendingRuns Permutation := List => w -> (
215-
-- inspired from the SageMath implementation
216-
-- https://github.com/sagemath/sage/blob/develop/src/sage/combinat/permutation.py
217-
if #w == 1 then allRuns := {toSequence w}
218-
else (
219-
allRuns = {};
220-
currentRun := {w#0};
221-
for wi in w_(toList(1 ..< #w)) do (
222-
if wi < last currentRun then currentRun = append(currentRun, wi)
223-
else (
224-
allRuns = append(allRuns, toSequence currentRun);
225-
currentRun = {wi};
226-
);
227-
);
228-
allRuns = append(allRuns, toSequence currentRun);
229-
);
230-
allRuns
231-
)
57+
load "./Permutations/Code/main.m2"
58+
load "./Permutations/Code/operations.m2"
59+
load "./Permutations/Code/patternAvoidance.m2"
23260

233-
exceedances = method(Options => {Weak => false})
234-
exceedances Permutation := List => opts -> w -> (
235-
compare := if opts.Weak then ((i,j) -> i <= j) else ((i,j) -> i < j);
236-
for i in 1 .. #w list if compare(i,w_i) then i else continue
237-
)
238-
239-
saliances = method()
240-
saliances Permutation := List => w -> (
241-
to1Index positions(1 .. #w, i -> all(i+1 .. #w, j -> w_i > w_j))
242-
)
243-
244-
records = method()
245-
records Permutation := List => w -> (
246-
to1Index positions(1 .. #w, i -> all(1 ..< i, j -> w_j < w_i))
247-
)
248-
249-
------------------------------------
250-
-- Pattern avoidance
251-
------------------------------------
252-
avoidsPattern = method(TypicalValue => Boolean)
253-
avoidsPattern (Permutation,List) := (w, pattern) -> (
254-
--assume permutation is pattern-avoiding, break if not true
255-
for idx in subsets(0 .. #w-1, #pattern) do {
256-
vals := w_(idx);
257-
sortedVals := sort(vals);
258-
relPositions := hashTable toList apply(0..#vals-1, i -> {sortedVals#i, i});
259-
p := toList apply(vals, i -> (relPositions#i) + 1);
260-
if p == pattern then return false;
261-
};
262-
true
263-
)
264-
265-
avoidsPatterns = method(TypicalValue => Boolean)
266-
avoidsPatterns (Permutation, List) := (w, patterns) -> (
267-
all(patterns, pattern -> avoidsPattern(w, pattern))
268-
)
269-
270-
isVexillary = method(TypicalValue => Boolean)
271-
isVexillary Permutation := (w) -> (
272-
avoidsPattern(w, {2,1,4,3})
273-
)
274-
275-
isCartwrightSturmfels = method(TypicalValue => Boolean)
276-
isCartwrightSturmfels Permutation := w -> (
277-
patterns := {{1,2,5,4,3},
278-
{1,3,2,5,4},
279-
{1,3,5,2,4},
280-
{1,3,5,4,2},
281-
{2,1,5,4,3},
282-
{1,2,5,3,6,4},
283-
{1,2,5,6,3,4},
284-
{2,1,5,3,6,4},
285-
{2,1,5,6,3,4},
286-
{3,1,5,2,6,4},
287-
{3,1,5,6,2,4},
288-
{3,1,5,6,4,2}};
289-
avoidsPatterns(w, patterns)
290-
)
291-
292-
isCDG = method(TypicalValue => Boolean)
293-
isCDG Permutation := w -> (
294-
patterns := {{1,3,2,5,4},
295-
{2,1,5,4,3},
296-
{2,1,4,6,3,5},
297-
{2,1,5,3,6,4},
298-
{2,1,5,6,3,4},
299-
{2,4,1,6,3,5},
300-
{3,1,5,2,6,4},
301-
{4,2,6,1,7,3,5}};
302-
avoidsPatterns(w, patterns)
303-
)
304-
305-
------------------------------------
306-
-- Foata's fundamental bijection
307-
------------------------------------
308-
-- see https://en.wikipedia.org/wiki/Permutation#Foata's_transition_lemma
309-
foataBijection = method()
310-
foataBijection Permutation := Permutation => w -> (
311-
permutation splice cycleDecomposition w
312-
)
313-
314-
------------------------------------
315-
-- Miscellaneous
316-
------------------------------------
317-
-- inverse = method()
318-
inverse Permutation := Permutation => w -> (permutation to1Index inversePermutation to0Index toList w)
319-
320-
-- order of a permutation, i.e. smallest integer n such that w^n = identity
321-
-- the order of a permutation can be expressed as the lcm of its cycle lengths
322-
ord = method()
323-
ord Permutation := ZZ => w -> (
324-
lcm((cycleDecomposition w) / length)
325-
)
326-
327-
-- see https://en.wikipedia.org/wiki/Parity_of_a_permutation for different ways
328-
-- to compute the sign or parity of a permutation
329-
sign Permutation := ZZ => w -> (
330-
if even(#w - #(cycleDecomposition w)) then 1 else -1
331-
)
332-
333-
isEven = method(TypicalValue => Boolean)
334-
isEven Permutation := w -> (
335-
sign w == 1
336-
)
337-
338-
isOdd = method(TypicalValue => Boolean)
339-
isOdd Permutation := w -> (
340-
sign w == -1
341-
)
342-
343-
isDerangement = method(TypicalValue => Boolean)
344-
isDerangement Permutation := w -> (not any(cycleDecomposition w, cycle -> #cycle == 1))
345-
346-
fixedPoints = method()
347-
fixedPoints Permutation := List => w -> (for cycle in cycleDecomposition w list if #cycle == 1 then unsequence cycle else continue)
348-
349-
inversions = method()
350-
inversions Permutation := List => w -> (
351-
for idxPair in sort(subsets(toList w, 2) / sort) list if w_(idxPair#0) > w_(idxPair#1) then idxPair else continue
352-
)
353-
354-
length Permutation := ZZ => w -> (#(inversions w))
35561

35662
-----------------------------------------------------------------------------
35763
-- **DOCUMENTATION** --
35864
-----------------------------------------------------------------------------
35965
beginDocumentation()
360-
load "./Permutations/docs.m2"
66+
load "./Permutations/Documentation/packageDocs.m2"
67+
load "./Permutations/Documentation/mainDocs.m2"
68+
load "./Permutations/Documentation/operationsDocs.m2"
69+
load "./Permutations/Documentation/patternAvoidanceDocs.m2"
70+
36171

36272
-----------------------------------------------------------------------------
36373
-- **TESTS** --
36474
-----------------------------------------------------------------------------
365-
load "./Permutations/tests.m2"
75+
load "./Permutations/Tests/mainTests.m2"
76+
load "./Permutations/Tests/operationsTests.m2"
77+
load "./Permutations/Tests/patternAvoidanceTests.m2"
36678
end
36779

80+
36881
-----------------------------------------------------------------------------
36982
--Development Section
37083
-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)