Package: permuta
Permuta is a Python library for working with perms (short for permutations),
patterns, and mesh patterns.If this code is useful to you in your work, please consider citing it. To generate a
BibTeX entry (or another format), click the “DOI” badge above and locate the “Cite As”
section.If you need support, you can join us in ourDiscord support server.InstallingTo install Permuta on your system, run:pipinstallpermutaIt is also possible to install Permuta in development mode to work on the
source code, in which case you run the following after cloning the repository:./setup.pydevelopTo run the unit tests:pipinstall-rtest_requirements.txt./setup.pytestUsing PermutaOnce you’ve installed Permuta, it can be imported by a Python script or an
interactive Python session, just like any other Python library:>>>frompermutaimport*Importing*from it supplies you with the ‘Perm’ and ‘PermSet’
classes along with the ‘AvoidanceClass’ class (with alias ‘Av’) for generating
perms avoiding a set of patterns. It also gives you the ‘MeshPatt’ class
and some other submodules which we will not discuss in this readme.Creating a single permPermutations are zero-based in Permuta and can be created using any iterable.>>>Perm()# Empty permPerm(())>>>Perm([])# Another empty permPerm(())>>>Perm((0,1,2,3))# The zero-based version of 1234Perm((0,1,2,3))>>>Perm((2,1,3))# Warning: it will initialise with any iterablePerm((2,1,3))Permutations can also be created using some specific class methods.>>>Perm.from_string("201")# stringsPerm((2,0,1))>>>Perm.one_based((1,3,2,4))# one-based iterable of integersPerm((0,2,1,3))>>>Perm.to_standard("a2gsv3")# standardising any iterable using '<'Perm((2,0,3,4,5,1))>>>Perm.from_integer(210)# an integer between 0 and 9876543210Perm((2,1,0))>>>Perm.from_integer(321)# any integer given is standardisedPerm((2,1,0))>>>Perm.from_integer(201)Perm((2,0,1))Printing perms gives zero-based strings.>>>print(Perm(()))ε>>>print(Perm((2,1,0)))210>>>print(Perm((6,2,10,9,3,8,0,1,5,11,4,7)))(6)(2)(10)(9)(3)(8)(0)(1)(5)(11)(4)(7)The avoids, contains, and occurrence methods enable working with patterns:>>>p=Perm((0,2,1,3))>>>p.contains(Perm((2,1,0)))False>>>p.avoids(Perm((0,1)))False>>>list(p.occurrences_of(Perm((1,0))))[(1,2)]>>>list(Perm((0,1)).occurrences_in(p))[(0,1),(0,2),(0,3),(1,3),(2,3)]The basic symmetries are implemented:>>>[p.reverse(),p.complement(),p.inverse()][Perm((3,1,2,0)),Perm((3,1,2,0)),Perm((0,2,1,3))]To take direct sums and skew sums we use+and-:>>>q=Perm((0,1,2,3,4))>>>p+qPerm((0,2,1,3,4,5,6,7,8))>>>p-qPerm((5,7,6,8,0,1,2,3,4))There are numerous practical methods available:>>>list(p.fixed_points())[0,3]>>>list(p.ascents())[0,2]>>>list(p.descents())[1]>>>list(p.inversions())[(1,2)]>>>p.major_index()2Creating a perm classPerm classes are specified with a basis:>>>basis=Basis(Perm((1,0,2)),Perm((1,2,0)))>>>basisBasis((Perm((1,0,2)),Perm((1,2,0))))>>>perm_class=Av(basis)>>>perm_classAv(Basis((Perm((1,0,2)),Perm((1,2,0)))))You can ask whether a perm belongs to the perm class:>>>Perm((3,2,1,0))inperm_classTrue>>>Perm((0,2,1,3))inperm_classFalseYou can get its enumeration up to a fixed length.>>>perm_class.enumeration(10)[1,1,2,4,8,16,32,64,128,256,512]>>>perm_class.count(11)1024You can also look to see if some well know enumeration strategies apply to a
given class.>>>frompermuta.enumeration_strategiesimportfind_strategies>>>basis=[Perm((3,2,0,1)),Perm((1,0,2,3))]>>>forstratinfind_strategies(basis):...print(strat.reference())Theinsertionencodingofpermutations:Corollary10>>>basis=[Perm((1,2,0,3)),Perm((2,0,1,3)),Perm((0,1,2,3))]>>>forstratinfind_strategies(basis):...print(strat.reference())EnumerationofPermutationClassesandWeightedLabelledIndependentSets:Corollary4.3Permutation statisticsWith thePermutationStatisticclass we can look for distributions of statistics for
classes and look for statistics preservations (or transformation) either for two classes
or given a bijection. First we need to import it.>>>frompermuta.permutils.statisticsimportPermutationStatisticTo see a distribution for a given statistic we grab its instance and provide a length
and a class (no class will use the set of all permutations).>>>PermutationStatistic.show_predefined_statistics()# Show all statistics with id[0]Numberofinversions[1]Numberofnon-inversions[2]Majorindex[3]Numberofdescents[4]Numberofascents[5]Numberofpeaks[6]Numberofvalleys[7]Numberofcycles[8]Numberofleft-to-rightminimas[9]Numberofleft-to-rightmaximas[10]Numberofright-to-leftminimas[11]Numberofright-to-leftmaximas[12]Numberoffixedpoints[13]Order[14]Longestincreasingsubsequence[15]Longestdecreasingsubsequence[16]Depth[17]Numberofbounces[18]Maximumdropsize[19]Numberofprimesinthecolumnsums[20]Holeynessofapermutation[21]Numberofstack-sortsneeded[22]Numberofpop-stack-sortsneeded[23]Numberofpinnacles[24]Numberofcyclicpeaks[25]Numberofcyclicvalleys[26]Numberofdoubleexcedance[27]Numberofdoubledrops[28]Numberofforemaxima[29]Numberofafterminima[30]Numberofaftermaxima[31]Numberofforeminima>>>depth=PermutationStatistic.get_by_index(16)>>>depth.distribution_for_length(5)[1,4,12,24,35,24,20]>>>depth.distribution_up_to(4,Av.from_string("123"))[[1],[1],[1,1],[0,2,3],[0,0,3,7,4]]Given a bijection as a dictionary, we can check which statistics are preserved withcheck_all_preservationsand which are transformed withcheck_all_transformed>>>bijection={p:p.reverse()forpinPerm.up_to_length(5)}>>>forstatinPermutationStatistic.check_all_preservations(bijection):...print(stat)NumberofpeaksNumberofvalleysHoleynessofapermutationNumberofpinnaclesWe can find all (predefined) statistics equally distributed over two permutation
classes withequally_distributed. We also support checks for joint distribution
of more than one statistics withjointly_equally_distributedand transformation
of jointly distributed stats withjointly_transformed_equally_distributed.>>>cls1=Av.from_string("2143,415263")>>>cls2=Av.from_string("3142")>>>forstatinPermutationStatistic.equally_distributed(cls1,cls2,6):...print(stat)MajorindexNumberofdescentsNumberofascentsNumberofpeaksNumberofvalleysNumberofleft-to-rightminimasNumberofright-to-leftmaximasLongestincreasingsubsequenceLongestdecreasingsubsequenceNumberofpinnaclesThe BiSC algorithmThe BiSC algorithm can tell you what mesh patterns are avoided by a set of
permutations. Although the output of the algorithm is only guaranteed to
describe the finite inputted set of permutations, the user usually hopes that
the patterns found by the algorithm describe an infinite set of permutatations.
To use the algorithm we first need to import it.>>>frompermuta.biscimport*A classic example of a set of permutations described by pattern avoidance are
the permutations sortable in one pass through a stack. We use the functionstack_sortablewhich returnsTruefor permutations that satisfy this
property. The user now has two choices: Runauto_bisc(Perm.stack_sortable)and let the algorithm run
without any more user input. It will try to use sensible values, starting by
learning small patterns from small permutations, and only considering longer
patterns when that fails. If the user wants to have more control over what
happens that is also possible and we now walk through that: We input the
property intobiscand ask it to search for patterns of length 3.>>>bisc(Perm.stack_sortable,3)Iwillusepermutationsuptolength7{3:{Perm((1,2,0)):[set()]}}When this command is run without specifying what length of permutations you
want to consider,biscwill create permutations up to length 7 that satisfy
the property of being stack-sortable. The output means: There is a single
length 3 pattern found, and its underlying classical pattern is the permutationPerm((1,2, 0)). Ignore the[set()]in the output for now. We can useshow_meto get a better visualization of the patterns found. In this call
to the algorithm we also specify that only permutations up to length 5 should
be considered.>>>SG=bisc(Perm.stack_sortable,3,5)>>>show_me(SG)Thereare1underlyingclassicalpatternsoflength3Thereare1differentshadingson120Thenumberofsetstomonitoratthestartoftheclean-upphaseis1<BLANKLINE>Nowdisplayingthepatterns<BLANKLINE>|||-+-●-+-|||-●-+-+-|||-+-+-●-|||<BLANKLINE>We should ignore theThe number of sets to monitor at the start of theclean-upphase is 1message for now.We do not really need this algorithm for sets of permutations described by the
avoidance of classical patterns. Its main purpose is to describe sets with mesh
patterns, such as the West-2-stack-sortable permutations>>>SG=bisc(Perm.west_2_stack_sortable,5,7)>>>show_me(SG)Thereare2underlyingclassicalpatternsoflength4Thereare1differentshadingson1230Thereare1differentshadingson2130Thenumberofsetstomonitoratthestartoftheclean-upphaseis1Thereare1underlyingclassicalpatternsoflength5Thereare1differentshadingson42130<BLANKLINE>Nowdisplayingthepatterns<BLANKLINE>||||-+-+-●-+-||||-+-●-+-+-||||-●-+-+-+-||||-+-+-+-●-||||<BLANKLINE>|▒|||-+-+-●-+-||||-●-+-+-+-||||-+-●-+-+-||||-+-+-+-●-||||<BLANKLINE>|▒||||-●-+-+-+-+-||▒|||-+-+-+-●-+-|||||-+-●-+-+-+-|||||-+-+-●-+-+-|||||-+-+-+-+-●-|||||<BLANKLINE>This is good news and bad news. Good because we quickly got a description of the
set we were looking at, that would have taken a long time to find by hand. The bad news
is that there is actually some redundancy in the output. To understand better what is
going on we will start by putting the permutations under investigation in a dictionary,
which keeps them separated by length.>>>A,B=create_bisc_input(7,Perm.west_2_stack_sortable)This creates two dictionaries with keys 1, 2, …, 7 such thatA[i]points
to the list of permutations of lengthithat are West-2-stack-sortable, andB[i]points to the complement. We can pass the A dictionary directly into
BiSC since only the permutations satisfying the property are used to find the
patterns. We can use the second dictionary to check whether every permutation
in the complement contains at least one of the patterns we found.>>>SG=bisc(A,5,7)>>>patterns_suffice_for_bad(SG,7,B)StartingsanitycheckwithbadpermsNowcheckingpermutationsoflength0Nowcheckingpermutationsoflength1Nowcheckingpermutationsoflength2Nowcheckingpermutationsoflength3Nowcheckingpermutationsoflength4Nowcheckingpermutationsoflength5Nowcheckingpermutationsoflength6Nowcheckingpermutationsoflength7Sanitycheckpassesforthebadperms(True,[])In this case it is true that every permutation in B, up to length 7, contains
at least one of the patterns found. Had that not been the case a list of
permutations would have been outputted (instead of just the empty list).Now, we claim that there is actually redundancy in the patterns we found, and
the length 4 mesh patterns should be enough to describe the set. This can occur
and it can be tricky to theoretically prove that one mesh pattern is implied
by another pattern (or a set of others, as is the case here). We use the dictionaryBagain and run>>>bases,dict_numbs_to_patts=run_clean_up(SG,B)<BLANKLINE>Thebasesfoundhavelengths[2]There is one basis of mesh patterns found, with 2 patterns>>>show_me_basis(bases[0],dict_numbs_to_patts)<BLANKLINE>Displayingthepatternsinthebasis<BLANKLINE>||||-+-+-●-+-||||-+-●-+-+-||||-●-+-+-+-||||-+-+-+-●-||||<BLANKLINE>|▒|||-+-+-●-+-||||-●-+-+-+-||||-+-●-+-+-||||-+-+-+-●-||||<BLANKLINE>This is the output we were expecting. There are several other properties of
permutations that can be imported frompermuta.bisc.perm_properties, such
assmooth,forest-like,baxter,simsun,quick_sortable, etc.Bothbiscandauto_bisccan accept input in the form of a property,
or a list of permutations (satisfying some property).LicenseBSD-3: see theLICENSEfile.CitingIf you found this library helpful with your research and would like to cite us,
you can use the followingBibTeXor go toZenodofor alternative formats.