Skip to content

Instantly share code, notes, and snippets.

@jksuom
Last active January 5, 2024 14:13
Show Gist options
  • Save jksuom/65ab555553fe35e31764 to your computer and use it in GitHub Desktop.
Save jksuom/65ab555553fe35e31764 to your computer and use it in GitHub Desktop.
On implementation of groups in SymPy

Groups defined by generators (and relators) are analogous to polynomial rings (and their quotient rings). In SymPy there are three different ways of representing polynomials: general expressions, and then dense and sparse representations. Expressions are convenient to use as they are essentially self-contained. But they are less efficient in computations while the other two are each best for specific purposes.

There could also be three types of representations for elements of groups.

Expressions would belong to a class GroupExpr or GrpExpr. They could be constructed from GrpSym's by means of GrpPow and GrpMul together with GrpUnit. There would also be methods such as inverse.

Moreover, group elements could be represented more efficiently as 'words', i.e., lists or tuples, over an alphabet that consists of (representatives of) generating symbols and their inverses. It seems that there are two practical alphabet implementations that are called 'syllables' and 'letters' in GAP. Syllables are essentially pairs of a symbol and an integer exponent. This allows for representing all positive and negative powers of a generator in addition to the inverse. Letters are just integers indexing the generators. Negative integers denote the inverse generators. Both of these could be implemented in SymPy.

In addition, there are different kinds of 'words' in GAP. When there are less than 128 generators, it is possible to pack a 'letter' into a single byte. However, it should be noted that GAP was conceived in a time when memory was an expensive resource. Since shuffling of bytes in a long word is not very efficient, it might be reasonable to be satisfied with standard Python lists and tuples instead of strings in a SymPy implementation.

Objects of class FreeGroup could be constructed by giving their generators as GrpSyms. In mathematics, two free groups are usually considered equal when they have the same generators. I think that could be so also in SymPy. Representations of elements should not be visible on this level. In fact, it seems that a single group object could allow all three different representations.

A GrpExpr would be considered as denoting an element of a group whenever its GrpSyms are among the generators. The group class would have methods transforming these into the two other representations. In addition, the two dense representations could be transformed into each other.

The dense representations would each belong to their own class. (I have not thought about their names yet.) Methods of these classes would include __mul__, __pow__ and inverse. As attributes they should probably have the group and the representation of unit.

Although the external interface to FreeGroup would not include representations, I think they would probably have to be taken into account in the way the generators are given as arguments. Mathematically, two free groups are considered equal when they have the same generators as sets. As the 'letter' representation obviously demands that the generators can be uniquely indexed, we have to add some order to the generator sets. The easiest way would probably be to just give a sequence of GrpSyms as an argument to FreeGroup. Another possibility could be defining a global order among all GrpSyms.

The above remarks could be easily extended to non-free groups. They would have two sets of parameters, generator GrpSyms and relator GrpExprs. The elements of such groups are mathematically sets (called 'cosets'), but they would be represented by suitably chosen representatives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment