11newPackage (
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" ,
991010 HomePage => " https://seangrate.com/" }
1111 },
12- Headline => " functions for working with permutations"
13- )
12+ Headline => " functions for working with permutations" ,
13+ PackageExports => { " Posets " } )
1414
1515export {
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-- ---------------------------------------------------------------------------
35965beginDocumentation ()
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"
36678end
36779
80+
36881-- ---------------------------------------------------------------------------
36982-- Development Section
37083-- ---------------------------------------------------------------------------
0 commit comments