So, these are some tips and tricks for using the library that might be helpful.
The crate consists of two main section
- perm
- group
The first section deals mostly with permutations, which are the basic data structure used. The second is where most of the interesting algorithms lies, which deal with groups generated by finitely many permutations.
The main object you will probably need to understand is the Group object. It stores a group as a finite list of generators, and it can be used for all sort of operations. Note that Group is actually a Group<P>, where P is of type DefaultPermutation. The rationale for this is that we would like in general to be not too verbose to specify a group, but allow the user to specify which permutation they might want. The Group object provides a library of commonly used group types, such as trivial, klein_4, dihedral_2n, cyclic, alternating, symmetric, which are all instantieted in the DefaultPermutation type. Also, it is always possible to create a Group<P> from an iterator of P using FromIterator
or from an array of P using Group::new.
We suggest that if the user desires to use other kind of permutation for those groups they create them and use the Group::map operation in the following way:
Group::symmetric(32).map(SyncPermutation::from)
Once a group object, say G, is created there are lot of methods that can be used.
This are simple methods to massage the generating set of G
deduplicate, make sure the generating set does not contain duplicatesrandom_generators, creates a new generating set, iteratively adding points and computing stabchains until the size matchesrandom_n_generators, tries to create a new generating set ofnelements, note this might not terminateconjugate_gens, conjugate all generators by a given element.
Ways to combine groups to get other groups, at the moment we only have product, which takes two groups and computes the cartesian product of the groups.
The methods:
rngrng_with_sourceare used to generate random elements in the group. The second one of course takes in a randomness source that can be used for different needs. They return aRandPermobject, which can be queried usingRandPerm::random_permutationto get as many permutations as wished (of course limited by the size of the group).
It is very important to be able to compute orbits and transversals in permutation groups. We provide these in three methods:
orbit, computes the orbit of a pointtransversal, computes the transversal of a pointfactored_transversal, computes the transversal of a point, stored in a factored manner.
Each method returns a struct with all the information easily queriable.
Each of these has an of_action version, which takes any element of a type that implements Action and allows to compute a general action. For example using MultiplicativeAction::default() will apply those methods with the multiplicative action.
Finally, here is core of the module, the stabchain operations.
We start with some glossary. A selector is a type that implements BaseSelector. It is used to control how the base is selected in a stabilizer chain
construction. There are three selectors and one adaptor that can be used to combine selectors:
LmpSelectorandFmpSelectorrespectively select the last and first moved point by the permutationFixedBaseSelectorselect a user defined basePartialSelectorcan be used to combine any two of the above selectors, it will use the first selector for the the initial prefix and then switch to the second selector. For examplePartialSelector::new(FixedBaseSelector::new(&base[0..3]), 3, LmpSelector::default());can be used to select the first 3 points of the fixed base and then switch to the default selection of using last moved point.
Now a strategy is a type that implements BuilderStrategy. It is supposed to be a lightweight struct that specifies how the stabilizer chain should be constructed. There are three main ways strategies:
NaiveBuilderStrategycomputes a stabilizer chain using the deterministic algorithm and building full transversal. Should be fastest for small groups.IFTBuilderStrategycomputes a stabilizer chain using the deterministic algorithm using a factored transversal. Slower than the previous one but should be more memory efficientRandomBuilderStrategyNaiveuses the random algorithm to compute stabilizer chainsRandomBuilderStrategyShallowuses the random algorithm with an optimization that makes the trees shallower
Each strategy can be created by passing in an action and a selector, and the random ones takes additionally some parameters that will be used in order to set up the constants for the algorithm.
The methods that are exposed on G are as following:
stabchaincomputes a stabilizer chain using the default strategy and the default selectorstabchain_basecomputes a stabilizer chain using the default strategy and a fixed basestabchain_with_selectorcomputes a stabilizer chain using the default strategy and a given selectorstabchain_with_strategycomputes a stabilizer chain using a given strategy (that will also include a given selector)
As with permutation, we have provided DefaultStrategy and DefaultSelector as type alias for the default strategy and selectors.
The main export of this module is the Permutation trait, which is an "interface" for a general group element. As such you can get an identity element, compute the multiplication of two permutations of the same type and the inverse of any permutation. What distinguishes such an object from a standard group element is that we can apply it to a point, so that we can use it to defines Action on a desired set. We provide many implementation of this permutation trait, namely:
DefaultPermutationThe default chosen type for a permutation. The idea is that it will be chosen to be the most advantageous and it can be changed at will. It defaults toStandardPermutation.StandardPermutationA permutation which stores a list of images in a reference counted array. Good all size fits all, not thread safe.SyncPermutationSame asStandardPermutation, but the reference counting is done atomically, making it the best choice for multithreaded applications.WordPermutation, a permutation that does lazy multiplication and application, can be useful for some operations such as in the random stabchain algorithmBasedPermutation, a permutation that stores an offset, and will fix all points before that offset. Very useful if you are dealing with things like products which are implemented by shifting permutationMapPermutation, a terrible permutation that stores the images as an HashMap. If it fixes many point it is very memory efficient, but benchmarks show that it is very slow so it is almost never the best choice.
Together with those we have some permutations that are to be used mostly for exporting and userfacing tasks, and as such they do not have computation capabilities. These are:
ClassicPermutationwhich creates a permutation on[1..n]from one on[0..n).CyclePermutationwhich computes the cycle representation of a permutationExportablePermutationwhich can be serialized with serde
All permutation types should be easily (some times not super efficiently) converted to one another, so for example you can seamlessly switch between StandardPermutation and SyncPermutation when needing to do something threaded.
So, the Action trait is used in order to specify different actions for the same permutation group. The idea is that often we can would like to apply the same algorithm with different kind of actions, and we can pass an instance of this interface to select at compile time what that action will be. We provide implementations for the following three:
SimpleApplication, uses theapplymethod inPermutation, so it computes an action on the point setConjugation, acts on the permutation group itself, and computes the conjugateMultiplication, acts on the permutation group itself by multiplying (on the right?)