SymPy Group Theory (GSoC 2017)2017-08-25T13:45:28+00:00http://valglad.github.ioValeriia Gladkovavaleriia.gladkova@gmail.comFinal Report2017-08-25T00:00:00+00:00http://valglad.github.io/2017/08/25/report<p>GSoC is coming to an end, and it’s time for the final report (which is not to say that I won’t make a couple more posts after this). In this post I will summarise the work I’ve done so far with links to PRs in approximately the order they were submitted.</p>
<p>First of all, looking at my <a href="https://github.com/sympy/sympy/wiki/GSoC-2017-Application-Valeriia-Gladkova:-Group-Theory">proposal</a>, I’d say that I have done all that was planned plus some minor additional things here and there (discovering and fixing bugs, modifying existing functions and occasionally adding new ones beyond what was planned). However, there is certainly room for improvement, and I will mention where the work could continue as I go through the PRs. So here it is.</p>
<ol>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12658">The <code class="highlighter-rouge">subgroup</code> method PR</a>. Here I added <code class="highlighter-rouge">subgroup()</code> methods to the <code class="highlighter-rouge">PermutationGroup</code> and <code class="highlighter-rouge">FpGroup</code> classes. There were some discussions as I wondered if <code class="highlighter-rouge">FreeGroup</code> class could be implemented differently, but it was mostly straightforward. Perhaps, it would be useful to add a keyword argument or something like that to <code class="highlighter-rouge">FpGroup</code>’s <code class="highlighter-rouge">subgroup()</code> to allow the user to get hold of the injective homomorphism from the subgroup to the parent group.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12681">Improvements to simplifying subgroup presentations.</a> I didn’t look at <code class="highlighter-rouge">_elimination_technique_2</code> because it is not used anywhere in the code at the moment but it could probably be improved as well, especially now
that some new <code class="highlighter-rouge">FreeGroupElement</code> methods are available: one of them is the general substitution of words that I implemented in this PR and, as I recall, I modified a few other <code class="highlighter-rouge">FreeGroupElement</code> methods there, as I discovered that some of them were buggy or not general enough. In a later PR (#9), I united the main elimination technique (which removes redundant generators) and the simplification of relators into one function <code class="highlighter-rouge">simplify_presentation</code> that can be applied to any group, not just as part of <code class="highlighter-rouge">reidemeister_presentation</code> (used for finding presentations of subgroups).</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12705">The Smith Normal form PR.</a> This is the only time I did work somewhere other than the <code class="highlighter-rouge">combinatorics</code> module during the project. I implemented the Smith Normal form for principal ideal domains because it could be used to test if a group is infinite (not a definitive test, as if the test is negative, we can’t conclude the group isn’t infinite). It’s a bit awkward to use at the moment because the user has to add manually a certain attribute to their matrix and it won’t be resolved until some further work is done on matrices. I wrote a bit more about it in the <a href="https://valglad.github.io/2017/06/05/smith/">relevant post</a>.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12761">Changing the order method</a>. The previous PR allowed returning <code class="highlighter-rouge">S.Infinity</code> as the order of the group in some cases where in the past the <code class="highlighter-rouge">order()</code> method wouldn’t terminate. This PR extended it even further by calculating the order in stages. First, it attempts to find a finite index subgroup and, if it succeeds, it finds the presentation of this subgroup and applies <code class="highlighter-rouge">order()</code> to it. In some cases, other methods can determine that this subgroup is infinite in which case, of course, the whole group is infinite. If it’s finite, then the order of the group is the index times the order of the subgroup. It is still possible that this never terminates if a finite index subgroup is not found, but it’s an improvement. It can be faster than direct coset enumeration on the trivial subgroup (that was used before) but occasionally it seems too slow for even smallish groups. Usually, the slowest part is finding the subgroup’s presentation but sometimes it’s the search for this subgroup that takes up the time. I feel that more work should be done here to make it more efficient.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12827">The homomorphism PR.</a> This was a substantial PR: not only did it introduce two new classes (<code class="highlighter-rouge">GroupHomomorphism</code> and <code class="highlighter-rouge">FpSubgroup</code>), it also involved quite a lot of work in the <code class="highlighter-rouge">PermutationGroup</code> class in order to implement the method that expresses a given permutation in terms of the group’s strong generators. At this stage only homomorphisms from <code class="highlighter-rouge">FpGroup</code> to <code class="highlighter-rouge">PermutationGroup</code> were fully implemented. The kernel computation can’t handle infinite domains - maybe, this could be addressed in the future.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12893">The Rewriting System PR.</a> This was probably the hardest thing in the project and it probably took the longest to get merged after its review started (or at least it felt the longest). Even after it did, some problems kept coming up. It seems stable at the moment but it could certainly do with more work. One thing that comes to mind is the reduction method: it is possible to do it more efficiently with an automaton which is built and modified as more reduction rules are added to the system. Also, perhaps, the completion algorithm could be made more efficient in some way.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12973">Fixing a bug in <code class="highlighter-rouge">reidemester_presentation</code>.</a> Discovered by accident, there was a small bug in <code class="highlighter-rouge">reidemeister_presentation</code> that led to <code class="highlighter-rouge">order()</code> returning wrong answers in some specific cases.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/13028">FpSubgroup’s <code class="highlighter-rouge">__contains__</code> method.</a> After the homomorphism PR was merged, it was discovered that occasionally the tests involving kernels would time out. This was because FpSubgroup’s <code class="highlighter-rouge">__contains__</code> method would go into an infinite loop on encountering elements of the conjugate form <code class="highlighter-rouge">a**-1*w*a</code>. It took some time to work out a way of dealing with it.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/12986">Finite presentation of permutation groups.</a> This is something I keep working on. The general algorithm is implemented and merged, however, the efficiency could potentially be improved by using a different method based on the group’s strong generating set. I have tried one implementation but it’s not clear when exactly it is more efficient. Currently, I am trying to implement a different, hopefully more consistently efficient, algorithm.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/13070">Fixing a bug in <code class="highlighter-rouge">minimal_block</code>.</a> A small bug in <code class="highlighter-rouge">minimal_block</code> was discovered during the implementation of sylow subgroups.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/1307">Adding the other homomorphism cases.</a> This PR enabled homomorphisms with <code class="highlighter-rouge">FpGroup</code> as codomain (became possible after merging the rewriting PR) and <code class="highlighter-rouge">PermutationGroup</code> as domain (provided the keyword argument <code class="highlighter-rouge">check</code> was set to <code class="highlighter-rouge">False</code>).</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/13104">Sylow subgroups PR.</a> This one also took a while. The main function is fairly long and it required implementation of two types of action homomorphisms and a method for finding all minimal block systems of a group. At the moment another related PR (#16) is being reviewed: it treats symmetric and alternating groups separately as the generators of their Sylow subgroups can be written down.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/13119">PermutationGroup methods for FpGroup.</a> This is something that gave me the idea for the project in the first place: many methods for permutation groups are already available while finitely presented groups have limited functionality. However, it’s possible to use an isomorphism between a finite FpGroup and a relevant permutation group to perform computations in the latter and then go back to the former. This is precisely what this PR does for many permutation group methods. It is still being reviewed.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/13138">Storing coset tables in <code class="highlighter-rouge">_finite_index_subgroup</code>.</a> Until the presentation PR, it wasn’t possible to get hold of an incomplete coset table for which coset enumeration returned with an error (for example if the maximum number of entries was exceeded). After it was merged, I made use of this new feature in the search for a finite index subgroup (used by <code class="highlighter-rouge">FpGroup</code>’s <code class="highlighter-rouge">order()</code> method). This somewhat decreased the required time as coset tables didn’t have to be recomputed.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/13151/">Checking that a homomorphism from PermutationGroup is well defined.</a> After the presentation PR was merged, it became possible to complete the homomorphism class by enabling the check for whether given generator images define a homomorphism when the domain is a permutation group. Not merged yet.</p>
</li>
<li>
<p><a href="https://github.com/sympy/sympy/pull/13150">Sylow subgroups for Sym(n) and Alt(n).</a> A separate method for computing Sylow subgroups of alternating and symmetric groups, to be used as part of the main <code class="highlighter-rouge">sylow_subgroup</code> method. This hugely improves the performance in the case of alternating and symmetric groups. Still being reviewed.</p>
</li>
</ol>
<p>A couple other PRs had to do with renaming attributes (<a href="https://github.com/sympy/sympy/pull/12732">this one</a> and <a href="https://github.com/sympy/sympy/pull/12719">this one</a>) or moving code around (for example, moving all of the coset table and coset enumeration functions to the file <code class="highlighter-rouge">coset_table.py</code> in <a href="https://github.com/sympy/sympy/pull/12947">this PR</a>). These didn’t include any actual work so I didn’t include them in the main list.</p>
<p>Hopefully, this report will be of use to whoever else might be interested in developing the group theory module. I plan to continue working on it myself for some time, though probably less productively as the new academic year starts soon.</p>
<p>Overall, this was a fun summer and I enjoyed working on this project. I’d like to thank Google for sponsoring it, SymPy for giving me the opportunity to participate and my mentor <a href="https://github.com/jksuom">Kalevi (jksuom)</a> for giving me guidance and useful suggestions on my code and generally being very helpful. :)</p>
Strong Presentation problems2017-08-22T00:00:00+00:00http://valglad.github.io/2017/08/22/strong-present<p>The final evaluation period has started, and I’ll be writing a post with the list of all submitted PRs and some summarising comments later this week (perhaps, tomorrow). Overall, I have done all that was planned though there is room for improvement as is the case with the finite presentation of permutation groups algorithm.</p>
<p>I have tried out computing a presentation on basic stabilizers, i.e. starting with the presentation of the smallest basic stabilizer and building up from it. This should probably be available in any case because it gives a strong presentation which could be desirable (it has more generators but on the other hand, fewer relators; theoretically, if known, these relators could be used to check if a homomorphism is well-defined a bit quicker). However, I was looking to see if this would be faster than the general version. What I found was that in some cases it’s considerably faster and in others much slower, with no clear pattern. For example, it doesn’t perfectly correlate with the size of the group or the number of strong generators. The slowest part is filling in the coset tables for intermediate presentations so I looked if the difference correlates with the index of the subgroup on which a presentation is built, or the difference between the generators of the subgroup and the original group, or their multiple (i.e. the size of the unfilled part of the table) and none of it properly accounts for the difference. There would seem to be a number of factors at play. I’m thinking of writing a simple function that generates a random group with a fixed degree and use it to collect data for the various parameters of many different groups. That might give me more to go on than the examples I make up myself. Not sure how successful this would be though. At the moment, I’m not certain I’d be able to figure it out by the end of this week. I’ll probably carry on the work until after the end of GSoC.</p>
<p>I sent a couple of small PRs last week. <a href="https://github.com/sympy/sympy/pull/13151/">One</a> for checking homomorphisms with permutation group domains (using the general presentation method for now) and <a href="https://github.com/sympy/sympy/pull/13150">the other</a> is with the more efficient method of computing Sylow subgroups of alternating and symmetric groups that I mentioned in the previous post. These two and the PR implementing permutation group methods for finitely presented groups are still being reviewed.</p>
<p>On a different note, lately I’ve been thinking of extending the <code class="highlighter-rouge">FreeGroupElement</code> class to handle group words with symbolic powers, e.g. <code class="highlighter-rouge">a**n</code> where <code class="highlighter-rouge">n</code> is an instance of <code class="highlighter-rouge">Symbol</code>. I don’t see any reason why it shouldn’t be available in general (though we’d have to be careful to raise errors where appropriate when someone tries to use this in methods; or to modify some methods to handle them if possible) and I was thinking of using something like this when implementing the <code class="highlighter-rouge">FpSubgroup</code> class so it can probably be put to use in some situations. One would also need to have a <code class="highlighter-rouge">subs</code> method for substituting desirable powers. This, along with the earlier idea of grouping things like <code class="highlighter-rouge">a*b*a*b</code> into <code class="highlighter-rouge">(a*b)**2</code>, could be another thing I could work on after GSoC.</p>
PermutationGroup methods for FpGroups2017-08-16T00:00:00+00:00http://valglad.github.io/2017/08/16/perm-to-fp<p>The <a href="https://github.com/sympy/sympy/pull/12986">presentation PR</a> got merged fairly quickly last week. Now I could try using the new functionality of resuming coset enumeration with incomplete coset tables in the <code class="highlighter-rouge">_finite_index_subgroup</code> function. I expect it should speed it up since at the moment the coset tables inside the function have to be recomputed every time the maximum number of allowed entries is increased. I could also implement a faster version of the presentation algortihm that makes use of strong generators.</p>
<p><a href="https://github.com/sympy/sympy/pull/13104">Sylow subgroups</a> required a bit more attention. One thing that we were discussing on the <a href="https://gitter.im/sympy/GroupTheory">Group Theory channel</a> the other day was that symmetric and alternating groups should be treated separately as the generators for their Sylow subgroups can be written down. It took some thinking to work out the details and justify the algorithm. In fact, the alternating group case still doesn’t have a formal proof; but it seems clear that it should work and, indeed, it does as I discovered yesterday on implementing the function. It was a bit fiddly to lay out the code so that it works properly and isn’t too complicated so it took a long time. Now all that remains is to tidy it up and add comments. I briefly described the algorithm in the docstring and hopefully it will make the code clear to whoever might need to work with it in the future. I think this can be added in a separate PR once the current one is merged, though if I have to make any more corrections to the current one, I might push this as well.</p>
<p>The title of the post is to do with the <a href="https://github.com/sympy/sympy/pull/13119">new PR</a> I sent this week in which I added some of the <code class="highlighter-rouge">PermutationGroup</code> methods to the <code class="highlighter-rouge">FpGroup</code> class so that they can work with finite instances of <code class="highlighter-rouge">FpGroup</code>. I didn’t actually need the presentation PR for it, homomorphisms were enough. At the moment, when a permutation group method returns a group, the equivalent fp group method returns its generators. An alternative to it would be to return an instance of <code class="highlighter-rouge">FpSubgroup</code> on the generators from where its <code class="highlighter-rouge">FpGroup</code> presentation can be found via <code class="highlighter-rouge">to_fp_group</code> method. Or, now that the presentation PR is merged, another possibility would be to run <code class="highlighter-rouge">presentation</code> on the permutation group returned by the permutation method and return the result together with a homomorphism from it to the original group - though that would probably be too time-consuming so shouldn’t be the default.</p>
<p>For the rest of this week, I’m going to keep working on the Sylow PR and the permutation group methods one if its review starts this week. I’ll also try to speed up the <code class="highlighter-rouge">_finite_index_subgroup</code> method and look into the strong generator algorithm for <code class="highlighter-rouge">FpGroup</code> presentations.</p>
Completing homomorphisms2017-08-08T00:00:00+00:00http://valglad.github.io/2017/08/08/complete<p>I sent the <a href="https://github.com/sympy/sympy/pull/1307">PR with the other homomorphism cases</a> a week ago, so about a day after my last post. The work required for the main part of the PR wasn’t really complicated but it took a while to get merged (earlier today) because some more problems showed up in the rewriting system part.</p>
<p>It started off with <a href="https://github.com/jksuom">Kalevi</a> noticing that in the case of a free abelian group, the list of rewriting rules after initiation seemed incomplete - it so happened that the test didn’t pick up on it because it didn’t need the missing rules. In itself, that wouldn’t be much of a problem because the missing rules could be added during the run of <code class="highlighter-rouge">make_confluent</code> but <code class="highlighter-rouge">is_confluent</code> was already <code class="highlighter-rouge">True</code> - that was definitely wrong. So for one thing, <code class="highlighter-rouge">_check_confluence</code> wasn’t working properly and also I thought that the type of rules that wasn’t added during rule initiation, could be added as another case - if it could be done in place, why wait till it’s discovered by the double loop in <code class="highlighter-rouge">make_confluent</code>. I made a few little changes throughout the code to fix things but ultimately, it was the inadequacy of <code class="highlighter-rouge">add_rule</code> that was causing problems.</p>
<p>When a pair of words is given to <code class="highlighter-rouge">add_rule</code>, it first multiplies them by the inverse of the first element of the longer word until the length difference is 0, 1 or 2 (greater length differences are redundant when the smaller length differences are in the rules dictionary). Then it does the same on the other (right) side which leads to a different set of rules. We could obtain even more rules right here, without waiting for <code class="highlighter-rouge">make_confluent</code>, if we allow switching sides, i.e. not just continuously multiplying on the right or on the left, but perform some left multiplications after several on the right, etc. This makes <code class="highlighter-rouge">make_confluent</code> a little more efficient as more rules are discovered at one time but trying all possible combinations of sides would probably take too much time without actually being productive. At the moment, when the length difference becomes sufficiently small, instead of adding the rule directly, <code class="highlighter-rouge">add_rule</code> calls itself recursively which allows for some side switching. Perhaps in the future, it would seem fit to try all combinations. A couple of days ago I added a rules cache to prevent repeating the work that has already been done by the function so maybe it won’t cause too much of a slow-down in practice.</p>
<p>After this, one rule was still missing. I reread the code several times and it took a while to work out that the problem was what seems quite obvious now. When a pair of words <code class="highlighter-rouge">w1, w2</code> of the same length is given to <code class="highlighter-rouge">add_rule</code>, the only rule that was added was <code class="highlighter-rouge">w1: w2</code> for <code class="highlighter-rouge">w1 > w2</code>. But another possibility right there could be <code class="highlighter-rouge">w2**-1: w1**-1</code> provided <code class="highlighter-rouge">w2**-1 > w1**-1</code>. Normally, this inverse rule doesn’t need to be added because if <code class="highlighter-rouge">len(w1) > len(w2)</code>, then <code class="highlighter-rouge">w1**-1 > w2**-1</code> and <code class="highlighter-rouge">w**-1: w2**-1</code> is implied by how word reduction is set up. Adding this last case solved the issue.</p>
<p>There were some other little improvements. For example, <code class="highlighter-rouge">make_confluent</code> has been made to returns a boolean at all times, not just when checking if the system is confluent. This could be used to see if it is successful. I also spotted an error in the kernel computation method that hadn’t come up before only by sheer luck.</p>
<p>Now that all the basic homomorphism functionality is available, I can have a go at extending the <code class="highlighter-rouge">FpGroup</code> class with <code class="highlighter-rouge">PermutationGroup</code> methods. I might be able to get it to work without the <a href="https://github.com/sympy/sympy/pull/12986">finite presentation of permutation groups PR</a> (it hasn’t been reviewed yet) but I’m not entirely sure yet.</p>
<p>Another thing on my hands is sylow subgroups. I actually thought I got them to work several days ago but then one of the test groups (<code class="highlighter-rouge">SymmetricGroup(10)</code>) revealed a bug in the <code class="highlighter-rouge">_strong_gens_slp</code> attribute. It wasn’t caused by the sylow method and only comes up after computing a stabilizer or a normalizer - something I only realised yesterday; this bug really confused me for a while. I did fix it now but a different problem came up and what worked before no longer does. I don’t see why the bug fix would lead to it but evidently it did… So still trying to sort it out.</p>
<p><strong>Update</strong>: Have just worked out that sylow thing. Turned out minimal blocks weren’t being computed properly (my fault: I wrote a separate function that should have outputed all minimal block systems but failed on minimality). So now all that remains is to do some more testing and tidy up the code, and I can send a PR with it in a day or so (if no other bugs turn up, that is).</p>
The rewriting PR and Sylow Subgroups2017-07-31T00:00:00+00:00http://valglad.github.io/2017/07/31/sylow<p>The <a href="https://github.com/sympy/sympy/pull/12893">rewriting PR</a> only got merged today. Firstly, it took several days to sort out the <code class="highlighter-rouge">FpSubgroup</code>’s <code class="highlighter-rouge">__contains__</code> method (in this <a href="https://github.com/sympy/sympy/pull/13028">PR</a>). Secondly, my mentor pointed out a case I overlooked in the <code class="highlighter-rouge">add_rule</code> routine, and once I corrected it, another problem presented itself. It wasn’t to do with <code class="highlighter-rouge">add_rule</code> but adding the overlooked case made it possible for the tests to pick up on it (luckily). The problem was that sometimes <code class="highlighter-rouge">make_confluent</code> would try to use a non-existent key for the dictionary of rewriting rules. This happened because <code class="highlighter-rouge">make_confluent</code> is set up in such a way that if sufficiently many rules are added, <code class="highlighter-rouge">_remove_redundancies</code> method is called, and this removes or modifies some of the existing rules, and the function didn’t account for this change properly. It took me several goes until I finally got it. And while I was at it, I noticed yet another bug which took some time to track down. Turned out that “for” loops don’t always properly iterate over lists that are changed inside the loop (spefically, they ignore newly appended elements). I didn’t think it would be a problem because I have done similar things before in python. I ended up replacing it with a “while” loop like:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>>>> while i < len(some_list):
>>> some_list.append(new_element)
>>> i += 1
</code></pre>
</div>
<p>and that worked properly. Still not entirely sure what happened there: appending elements inside a for loop in the terminal shell doesn’t cause such problems - I should probably look into that more at some point, for future reference.</p>
<p>So I only began working on completing the other homomorphism cases today (not counting what I have sketched in the previous couple of weeks). I’ll try to send a PR with some of it in several days. At this point, I should be able to do everything except checking that a homomorphism from a permutation group is well defined. For that I’ll need the <a href="https://github.com/sympy/sympy/pull/12986/">presentation PR</a> and it’s quite substantial so its review will almost certaintly take more than several days. I’m planning to add the keyword argument <code class="highlighter-rouge">check</code> to the <code class="highlighter-rouge">homomorphism</code> function so that if <code class="highlighter-rouge">check==False</code>, the given images are assumed to define a homomorphism. I found it useful in some of the work I was doing last week.</p>
<p>I decided to work on computing sylow subgroups, and as part of it, wrote two new homomorphism functions specifically for permutation groups: <code class="highlighter-rouge">orbit_action_homomorphism</code> and <code class="highlighter-rouge">block_action_homomorphism</code> for defining homomorphisms induced by the action of the group on a union of orbits or a block system respectively. These are of course homomorphisms between permutation groups and there is no need to check if they are well-defined so it was possible to create them without the presentation PR. I don’t know if it will stay that way as it hasn’t been discussed yet but it seemed appropriate to have them as separate functions in the homomorphisms file. Also, I found a bug in the <code class="highlighter-rouge">minimal_block</code> method while testing <code class="highlighter-rouge">block_action_homomorphism</code> yesterday but it’s not anything major and the <a href="https://github.com/sympy/sympy/pull/13070">fix</a> for it will likely be merged soon. There was some trouble with Travis today though.</p>
<p>The actual computation of sylow subgroups is going to be a <code class="highlighter-rouge">PermutationGroup</code> method <code class="highlighter-rouge">sylow_subgroup()</code> and it already works for some cases so it’s going well. However, I am going to pause it for now to finish homomorphisms.</p>
Delays2017-07-24T00:00:00+00:00http://valglad.github.io/2017/07/24/delays<p>The rewriting PR hasn’t been merged yet. At the beginning of last week, there was still some work to be done on it. For example, the <code class="highlighter-rouge">RewritingSystem</code>’s <code class="highlighter-rouge">check_confluence()</code> method (which, unsurprisingly, checks if the system is confluent) would add new rewriting rules while it runs - definitely not something it should do. Another addition, suggested by my mentor, was the attribute <code class="highlighter-rouge">_max_exceeded</code>: this is <code class="highlighter-rouge">True</code> when the Knuth-Bendix completion method has already been attempted but the maximum number of rules allowed to be added to the system was exceeded. Trying again would be a waste of time. However, if the maximum number of rules is increased, <code class="highlighter-rouge">_max_exceeded</code> is reset so that the completion method could be run again.</p>
<p>Then I worked on the multi-step version of the presentation algorithm (which was possible because the homomorphism <a href="https://github.com/sympy/sympy/pull/12827">PR</a> was merged by then). Once I wrote it up, made sure it worked and started testing against the single step one, I noticed that the multi-step version ran several times as fast for several of the groups I was using and yet was suddenly much slower for a group of higher order. This was unexpected and I spent a while trying to work out why that would be. The reason was this: the function uses <code class="highlighter-rouge">coset_enumeration_c</code> for filling in a certain coset table. <code class="highlighter-rouge">coset_enumeration_c</code> stores the deductions it makes while filling in so that it can process them later. However, if there are too many deductions, it’s not practical to go through all of them so the algorithm uses the method <code class="highlighter-rouge">look_ahead</code> that allows it to continue without looking at the deduction stack which is emptied. The critical size of the deduction stack was 500 by default. For large groups, the single step version would greatly exceed that most of the time so <code class="highlighter-rouge">look_ahead</code> was run instead, speeding it up considerably, while the multi step version would be working with a smaller coset table and the number of deductions would be large but not over 500 which made it slow. So it looked like processing close to 500 deductions was inefficient and I reduced the number to 100 to see what happens. What happened was that both version got faster but now the multi-step version was consistently faster than the single-step one. I ran the coset table tests and they seemed to be fine too so the reduction in the maximum number of deductions didn’t seem to affect anything negatively. I pushed the multi step version into the presentation <a href="https://github.com/sympy/sympy/pull/12986">PR</a> but that hasn’t started being reviewed because another problem came up.</p>
<p>The homomorphisms tests from the merged PR would occasionally time out so that needed investigating. Turned out it was because the <code class="highlighter-rouge">__contains__</code> method of the <code class="highlighter-rouge">FpSubgroup</code> class couldn’t handle group elements in the conjugate form, i.e. something of the form <code class="highlighter-rouge">r**-1*w*r</code> for some words <code class="highlighter-rouge">r, w</code>. It would get into an infinite loop and the tests would only occasionally time out because the method is used during kernel computation which is randomised. So a couple of days was spent thinking about what would be the best way to eliminate the problem, whether this sort of problem would only be caused by conjugate elements and finally expanding the code accordingly. You can follow what I did in this <a href="https://github.com/sympy/sympy/pull/13028">PR</a>. Though this is still being discussed and it’s unclear whether some other solution would be called for.</p>
<p>So because of all this, I couldn’t work on the other homomorphism cases (though I did sketch some things that I can use once the dependent PRs are merged). If the <code class="highlighter-rouge">FpSubgroup</code> issue is resolved soon and the rewriting PR is merged, I will implement homomorphisms to <code class="highlighter-rouge">FpGroup</code>s. The presentation PR will probably need more reviewing and I can’t implement <code class="highlighter-rouge">PermutationGroup</code> domains without it. I’m considering looking into an alternative method of doing homomorphisms specifically for the <code class="highlighter-rouge">PermutationGroup</code> to <code class="highlighter-rouge">PermutationGroup</code> case because I’ve seen a section on it in the Handbook. Or I could start working on Sylow subgroups which is another things I was thinking of doing. These things shouldn’t depend on any of the unmerged PRs so it would be a good use of time.</p>
Presentations of Permutation Groups2017-07-17T00:00:00+00:00http://valglad.github.io/2017/07/17/presentation<p>The work on finding finite presentations of permutation groups was somewhat delayed last week because I’ve come across a bug in the <code class="highlighter-rouge">reidemester_presentation</code> code while testing the one step version of the presetation algorithm (which is essentially finished). Turned out it was caused by an unnecessary cyclic reduction on one line in the main elimination technique. See <a href="https://github.com/sympy/sympy/pull/12973">PR</a> for the explanation.</p>
<p>Another delay was because I realised that for the multi-step version, it would be useful to have the homomorphism <a href="https://github.com/sympy/sympy/pull/12827">PR</a> merged. Mostly this is because of the <code class="highlighter-rouge">generator_product</code> method from the <code class="highlighter-rouge">PermutationGroup</code> class - this takes an arbitrary permutation in the group and returns a list of the strong generators such that the product of the elements of the list is equal to this permutation. But the homomorphism functionality that’s already there (the case of the homomorphism from an <code class="highlighter-rouge">FpGroup</code> to a <code class="highlighter-rouge">PermutationGroup</code>) would be helpful too. So I switched by attention to getting that PR ready for merging.</p>
<p>So this week I’ll try to add the multistep version and will also start implementing homomorphisms from <code class="highlighter-rouge">PermutationGroup</code>s and to <code class="highlighter-rouge">FpGroup</code>s, as outlined in the plan. Also, at some point when the rewriting PR is merged, I could try out the potentially improved random element generator for <code class="highlighter-rouge">FpGroup</code>s that I sketched a couple of weeks ago. This is not officially part of the plan and not in any way urgent, but could probably give better random elements which would be useful for the <code class="highlighter-rouge">order()</code> method and the kernel calculation for homomorphisms. Though I might not actually get around to it this week.</p>
The Rewriting System class2017-07-10T00:00:00+00:00http://valglad.github.io/2017/07/10/rewriting<p>I sent the <a href="https://github.com/sympy/sympy/pull/12893">PR</a> with the rewriting system implementation on Wednesday night, i.e. by Thursday as planned. It could have been earlier if I hadn’t spent one day experimenting with making the elements of <code class="highlighter-rouge">FpGroup</code> different from the underlying <code class="highlighter-rouge">FreeGroup</code>. At the moment they are the same so that, for instance:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>>>> F, a, b = free_group('a, b')
>>> G = FpGroup(F, [a**2, a*b*a**-1*b**-1])
>>> a in F
True
>>> a in G
True
</code></pre>
</div>
<p>Theoretically, since <code class="highlighter-rouge">F</code> and <code class="highlighter-rouge">G</code> are different groups (not even isomorphic), it would make sense for their elements to be represented by different objects, e.g. the generators for <code class="highlighter-rouge">G</code> could be <code class="highlighter-rouge">a_1, b_1</code> so that <code class="highlighter-rouge">G</code> and <code class="highlighter-rouge">F</code> are connected by the injective homomorphism sending <code class="highlighter-rouge">a_1</code> and <code class="highlighter-rouge">b_1</code> to <code class="highlighter-rouge">a</code> and <code class="highlighter-rouge">b</code> respectively. Though, for convenience, it could be allowed to refer to the elements of an <code class="highlighter-rouge">FpGroup</code> by the names of the underlying free group elements (and performing the conversion to <code class="highlighter-rouge">a_1</code> and <code class="highlighter-rouge">b_1</code> backstage before passing them onto <code class="highlighter-rouge">FpGroup</code>’s methods).</p>
<p>Now, if this were done, it would be possible to check for equality of two elements of <code class="highlighter-rouge">FpGroup</code> using the <code class="highlighter-rouge">==</code> syntax. E.g., if the generators of <code class="highlighter-rouge">G</code> were made distinct from <code class="highlighter-rouge">a, b</code> and called <code class="highlighter-rouge">a_1, b_1</code>, then we could have <code class="highlighter-rouge">a_1*b_1 == b_1*a_1</code> (while, of course, <code class="highlighter-rouge">a*b == b*a</code> is not true because <code class="highlighter-rouge">a</code> and <code class="highlighter-rouge">b</code> are the elements of a <code class="highlighter-rouge">FreeGroup</code>). The latter was the main motivation for trying this out but in the end, after additionally discussing things with my mentor, I left everything as it is and implemented a couple new <code class="highlighter-rouge">FpGroup</code> methods instead. So, for example, to check if <code class="highlighter-rouge">a*b</code> and <code class="highlighter-rouge">b*a</code> are equal in <code class="highlighter-rouge">G</code>, one would call <code class="highlighter-rouge">G.equals(a*b, b*a)</code>. The PR has more details.</p>
<p>At the moment I’m in the middle of writing the function for finding finite presentations of permutation groups. I’m slightly modifying the coset enumeration code to allow it to return an incomplete <code class="highlighter-rouge">CosetTable</code> (instead of raising a <code class="highlighter-rouge">ValueError</code> if, say, the maximum number of cosets is exceeded) and to start running with a partially filled table (which could be passed as a keyword argument) rather than with a new, empty instance. This is necessary as finding the presentation requires setting some of the coset table entries manually and adding relators to the future presentation while examining the undefined table entries, after which coset enumeration could be used to make more deductions. Messing with coset enumeration is the only complicated part (as far as I can see): the rest is pretty much sorted by now. I suppose, the only other thing is deciding when to find the presentation in one step and when to use the multi-step version (finding the presentation of a subgroup first and then the whole presentation based on that). The latter can be more efficient for larger groups. But I could think about that later, maybe run some tests, once the coset enumeration is set up properly.</p>
The Plan (Part II)2017-07-02T00:00:00+00:00http://valglad.github.io/2017/07/02/plan2<p>At the beginning of this week I finished writing the first draft of the homomorphism class, at least as much of it as is possible without the rewriting systems for <code class="highlighter-rouge">FpGroup</code>s. Homomorphisms from <code class="highlighter-rouge">FpGroup</code>s to <code class="highlighter-rouge">PermutationGroup</code>s are fully implemented though I’m sure corrections will be made as the <a href="https://github.com/sympy/sympy/pull/12827">PR</a> is reviewed. I mentioned that I wasn’t planning on sending the PR until after the rewriting systems but there is quite a bit there and a lot of it can be reviewed (and even merged) now.</p>
<p>It took a bit longer than I expected because the rewriting for permutation groups wasn’t quite what was necessary for homomorphisms. I knew that there was a function returning the unique normal form of a permutation in the group (the <code class="highlighter-rouge">coset_factor()</code> method) and had assumed that that would be enough but the normal form wasn’t in terms of the generators, nor was there an easy way to rewrite it in terms of the generators. So I had to modify the <code class="highlighter-rouge">schreier_sims()</code> method that finds the strong generating set and the elements that make up the normal form returned by <code class="highlighter-rouge">coset_factor()</code> to keep track of which generators in what order are multiplied to obtain them. Then I wrote a method that would write any permutation in the group as a product of the strong generators and, since I had the information about the make-up of the strong generators, this could easily be rewritten in terms of the original generators. Doing this was a bit fiddly and took a while. Though I suppose it could be counted as part of the work on rewriting systems.</p>
<p>The rewriting systems for <code class="highlighter-rouge">FpGroup</code>s are coming along. At the moment, it is a new class <code class="highlighter-rouge">RewritingSystem</code> which <code class="highlighter-rouge">FpGroup</code>s will probably have an attribute for. I’ve almost finished implementing the Knuth-Bendix completion algorithm and that was most of the work. Though there is also the matter of reduction. At the moment I’m using the <code class="highlighter-rouge">eliminate_words()</code> method from the <code class="highlighter-rouge">FreeGroupElement</code> class - it takes a dictionary of substitutions (in this case a dictionary of reduction rules) and substitutes all of them into a given word, if possible. But that isn’t very efficient for long words and large reduction dictionaries since <code class="highlighter-rouge">eliminate_words()</code> will scan the word from the start every time it tries to perform a new substitution. The approach I’ve seen described in papers on rewriting systems is to construct a finite automaton to perform the reduction and modify it every time a new rule is added. This would somewhat increase the time taken to initiate the system and to make it confluent but would also make word reductions much quicker. However, it could also take a while to actually implement. I’m unsure if it’s worth doing it now - perhaps, I could add it later, when the rest of my project is done.</p>
<p>Anyway, I was going to use this post to outline a schedule for this month’s work, like I did in the first post. Looking back at the Timeline I sketched in my <a href="https://github.com/sympy/sympy/wiki/GSoC-2017-Application-Valeriia-Gladkova:-Group-Theory">proposal</a>, I seem to have given myself 2 weeks for implementing the rewriting systems. This estimate wasn’t unreasonable, considering the unexpected matter of rewriting in permutation groups I had to deal with in the first half of the week and the reading I had to do to get a better idea of Knuth-Bendix. But if I don’t implement finite automatons for reductions right now, I think I should be able to send the rewriting PR by Thursday (probably earlier). With this in mind, my plan for the month is roughly as follows.</p>
<h3 id="the-plan-continued">The Plan (continued)</h3>
<ul>
<li>3 July - 6 July: finish the <code class="highlighter-rouge">RewritingSystem</code> class.</li>
<li>6 July - 16 July: implement finite presentations for <code class="highlighter-rouge">PermutationGroup</code>s (this should be plenty of time considering that I made a start on this during the application period)</li>
<li>17 July - 23 July: complete the homomorphism implementation to allow homomorphisms from <code class="highlighter-rouge">PermutationGroup</code>s and to <code class="highlighter-rouge">FpGroup</code>s. Implement the permutation presentation for finite <code class="highlighter-rouge">FpGroup</code>s.</li>
<li>24 July - 30 July: Set up the use of <code class="highlighter-rouge">PermutationGroup</code> methods for <code class="highlighter-rouge">FpGroup</code>s via homomorphisms.</li>
</ul>
<p>So by the end of the month, the homomorphism functionality should be complete, so should be the switching between <code class="highlighter-rouge">FpGroup</code> and <code class="highlighter-rouge">PermutationGroup</code> presentations (where it is possible, i.e. finite <code class="highlighter-rouge">FpGroup</code>s). Making <code class="highlighter-rouge">PermutationGroup</code> methods work for <code class="highlighter-rouge">FpGroup</code>s properly could take more time but if everything goes more or less according to plan, I should have most of August to try and implement Sylow subgroups for <code class="highlighter-rouge">PermutationGroup</code>s (there is a chapter on it in “The Handbook of Computational Group Theory”), look into the construction of finite automatons for word reduction or automatically grouping subwords of group words, like <code class="highlighter-rouge">(a*b)**2</code> instead of <code class="highlighter-rouge">a*b*a*b</code>, or anything else project-related really. That’s the optimistic scenario of course, provided no sudden terrible complications arise which can never be guaranteed.</p>
The homomorphism class2017-06-25T00:00:00+00:00http://valglad.github.io/2017/06/25/homomorphism<p>At the beginning of the week, all of my previous PRs got merged. This is good. Also, the homomorphism class is now mostly written with the exception of the kernel computation. The kernel is the only tricky bit. I don’t think there is any general method of computing it, but there is a way for finite groups. Suppose we have a homomorphism <code class="highlighter-rouge">phi</code> from a finite group <code class="highlighter-rouge">G</code>. If <code class="highlighter-rouge">g</code> is an element of <code class="highlighter-rouge">G</code> and <code class="highlighter-rouge">phi.invert(h)</code> returns an element of the preimage of <code class="highlighter-rouge">h</code> under <code class="highlighter-rouge">phi</code>, then <code class="highlighter-rouge">g*phi.invert(phi(g))**-1</code> is an element of the kernel (note that this is not necessarily the identity as the preimage of <code class="highlighter-rouge">phi(g)</code> can contain other elements beside <code class="highlighter-rouge">g</code>). With this in mind, we could start by defining <code class="highlighter-rouge">K</code> to be the trivial subgroup of <code class="highlighter-rouge">G</code>. If <code class="highlighter-rouge">K.order()*phi.image().order() == G.order()</code>, then we are done. If not, generate some random elements until <code class="highlighter-rouge">g*phi.invert(phi(g))**-1</code> is not the identity, and redefine <code class="highlighter-rouge">K</code> to be the subgroup generated by <code class="highlighter-rouge">g*phi.invert(phi(g))**-1</code>. Continue adding generators like this until <code class="highlighter-rouge">K.order()*phi.image().order() == G.order()</code> or finite <code class="highlighter-rouge">G</code> this will always terminate (or rather almost always considering that the elements are generated randomly - though it would only not terminate if at least one of the elements of <code class="highlighter-rouge">G</code> is never generated which is practically impossible).</p>
<p>This is how I am going to implement it. I haven’t already because I’ve been thinking about some of the details of the implementation. One thing that could be problematic is multiple calls to <code class="highlighter-rouge">reidemeister_presentation()</code> to compute the presentation of <code class="highlighter-rouge">K</code> at each step. As I’ve discovered when I was implementing the search for finite index subgroups last week, this can be very inefficient if the index of <code class="highlighter-rouge">K</code> is large (which it could well be for a small number of generators at the start). After giving it some thought, I realised that actually we could completely avoid finding the presentation because <code class="highlighter-rouge">K</code>’s coset table would be enough to calculate the order and check if an element belongs to it. Assuming <code class="highlighter-rouge">G</code> is finite, <code class="highlighter-rouge">K.order()</code> can be calculated as the order of <code class="highlighter-rouge">G</code> divided by the length of the coset table so the knowledge of the generators is enough. And for membership testing, all that’s necessary is to check if a given element stabilises <code class="highlighter-rouge">K</code> with the respect to the action on the cosets described by the coset table. And that should be a huge improvement over the obvious calls to the <code class="highlighter-rouge">subgroup()</code> method.</p>
<p>Actually, <code class="highlighter-rouge">FpGroup</code>s doesn’t currently have a <code class="highlighter-rouge">__contains__()</code> method so one can’t check if a word <code class="highlighter-rouge">w</code> is in a group <code class="highlighter-rouge">G</code> using <code class="highlighter-rouge">w in G</code>. This is easy to correct. What I was wondering was if we wanted to be able to check if words over <code class="highlighter-rouge">G</code> belong to a subgroup of <code class="highlighter-rouge">G</code> created with the <code class="highlighter-rouge">subgroup()</code> method - that wouldn’t be possible directly because <code class="highlighter-rouge">subgroup()</code> returns a group on a different set of generators but it wouldn’t be too unreasonable to have SymPy do this:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>>>> F, a, b = free_group('a, b')
>>> G = FpGroup(F, [a**3, b**2, (a*b)**2])
>>> K = G.subgroup([a])
>>> a**2 in K
True
</code></pre>
</div>
<p>I asked <a href="https://github.com/jksuom">Kalevi</a> about it earlier today and they said that it would be preferable to treat <code class="highlighter-rouge">K</code> in this case as a different group that happens to be linked to <code class="highlighter-rouge">G</code> through an injective homomorphism (essentially the canonical inclusion map). If we call this homomorphism <code class="highlighter-rouge">phi</code>, then the user can check if an element of <code class="highlighter-rouge">G</code> belongs to the subgroup represented by <code class="highlighter-rouge">K</code> like so: <code class="highlighter-rouge">a**2 in phi.image()</code>. Here <code class="highlighter-rouge">phi.image()</code> wouldn’t be an instance of <code class="highlighter-rouge">FpGroup</code> but rather of a new class <code class="highlighter-rouge">FpSubgroup</code> that I wrote today - it is a way to represent a subgroup of a group while keeping the same generators as in the original group. It’s only attributes are <code class="highlighter-rouge">generators</code>, <code class="highlighter-rouge">parent</code> (the original group) and <code class="highlighter-rouge">C</code> (the coset table of the original group by the subgroup) and it has a <code class="highlighter-rouge">__contains__</code>, an <code class="highlighter-rouge">order()</code> and a <code class="highlighter-rouge">to_FpGroup()</code> methods (the names are self-explanatory). For finite parent groups, the order is calculated as I described above for the kernel and for the infinite ones <code class="highlighter-rouge">redeimeister_presentation()</code> has to be called. The injective homomorphism from an instance of <code class="highlighter-rouge">FpGroup</code> returned by <code class="highlighter-rouge">subgroup()</code> would need to be worked out during the running of <code class="highlighter-rouge">reidemeister_presentation()</code> when the schreier generators are defined - this is still to be done.</p>
<p>Another thing I implemented this week was an improved method for generating random elements of finitely presented groups. However, when I tried it out to see how random the elements looked, I got huge words even for small groups so I didn’t send a PR with it yet. Once I implement rewriting systems, these words could be reduced to much shorter ones. Speaking of rewriting systems, I think it could be good if the rewriting was applied automatically much like <code class="highlighter-rouge">x*x**-1</code> is removed for <code class="highlighter-rouge">FreeGroupElement</code>s. Though I suppose this could be too inefficient some times - this would need testing. This is what I’ll be working on this week.</p>
The order method2017-06-18T00:00:00+00:00http://valglad.github.io/2017/06/18/order<p>Last week and some of this one I was working on changing the <code class="highlighter-rouge">order()</code> method of <code class="highlighter-rouge">FpGroup</code>s. Currently SymPy attempts to perform coset enumeration on the trivial subgroup and, if it terminates, the order of the group is the length of the coset table. A somewhat better way, at least theoretically, is to try and find a subgroup of finite index and compute the order of this subgroup separately. The function I’ve implemented only looks for a finite index subgroup generated by a subset of the group’s generators with a pseudo-random element thrown in (this can sometimes give smaller index subgroups and make the computation faster). The PR is <a href="https://github.com/sympy/sympy/pull/12761">here</a>.</p>
<p>The idea is to split the list of generators (with a random element) into two halves and try coset enumeration on one of the halves. To make sure this doesn’t go on for too long, it is necessary to limit the number of cosets that the coset enumeration algorithm is allowed to define. (Currently, the only way to set the maximum number of cosets is by changing the class variable <code class="highlighter-rouge">CosetTable.coset_table_max_limit</code> which is very large (4096000) by default - in the PR, I added a keyword argument to all functions relevant to coset enumeration so that the maximum can be set when calling the function.) If the coset enumeration fails (because the maximum number of cosets was exceeded), try the other half. If this doesn’t succeed, double the maximum number of cosets and try again. Once (if) a suitable subgroup is found, the order of the group is just the index times the order of the subgroup. The latter is computed in the same way by having <code class="highlighter-rouge">order()</code> call itself recursively.</p>
<p>The implementation wasn’t hard in itself but I did notice that finding the subgroup’s presentation was taking far too long in certain cases (specifically when the subgroup’s index wasn’t small enough) and spent a while trying to think of a way around it. I think that for cyclic subgroups, there is a way to calculate the order during coset enumeration without having to find the presentation explicitly but I couldn’t quite work out how to do that. Perhaps, I will eventually find a way and implement it. For now, I left it as it is. For large groups, coset enumeration will take a long time anyway and at least the new way will be faster in some cases and may also be able to tell if a group is infinite (while coset enumeration on the trivial subgroup wouldn’t terminate at all).</p>
<p>Now I am going to actually start working on homomorphisms which will be the main and largest part of my project. I’ll begin by writing the <code class="highlighter-rouge">GroupHomomorphism</code> class in this coming week. This won’t actually become a PR for a while but it is easier to do it first because I still have exams in the next several days. After that I’ll implement the Knuth-Bendix algorithm for rewriting systems (I might make a start on this later this week as I’ll have more time once the exams are over). Then I’ll send a PR with rewriting systems and once that’s merged, the <code class="highlighter-rouge">GroupHomomorphism</code> class one, because it would depend on rewriting systems.</p>
The Smith Normal Form2017-06-05T00:00:00+00:00http://valglad.github.io/2017/06/05/smith<p>Last week I was working on implementing the Smith Normal Form for matrices over principal ideal domains. I’m still making corrections as the <a href="https://github.com/sympy/sympy/pull/12705">PR</a> is being reviewed. I used the standard algorithm: use invertable (in the ring) row and column operations to make the matrix diagonal and make sure the diagonal entries have the property that an entry divides all of the entries that come after it (this is described in more detail on <a href="https://en.wikipedia.org/wiki/Smith_normal_form#Algorithm">wikipedia</a> for example). I ran into trouble when trying to determine the domain of the matrix entries if the user hadn’t explicitly specified one. Matrices in SymPy don’t have a <code class="highlighter-rouge">.domain</code> attribute or anything similar, and can contain objects of different types. So, if I did attempt to find some suitable principal ideal domain over which to consider all of them, the only way would be to try a few of the ones that are currently implemented until something fits, and that would have to be extended every time a new domain is implemented and generally sounds tedious to do. I’ve asked on the <a href="https://gitter.im/sympy/GroupTheory">Group Theory channel</a> if there was a better way and that started a discussion about changing the <code class="highlighter-rouge">Matrix</code> class to have a <code class="highlighter-rouge">.domain</code> or a <code class="highlighter-rouge">.ring</code> attribute and have the entries checked at construction. In fact, this has been brought up by other people before as well. Unfortunately, adding this attribute would require going over the matrix methods implemented so far and making sure they don’t assume anything that might not hold for general rings (especially non-commutative ones: like the determinant in its traditional form wouldn’t even make sense; however, it turns out there are several generalisations of determinants to non-commutative rings like <a href="https://en.wikipedia.org/wiki/Quasideterminant">quasideterminants</a> and <a href="https://en.wikipedia.org/wiki/Dieudonn%C3%A9_determinant">Dieudonné determinant</a>). And this would probably take quite a while and is not directly related to my project. So in the end we decided to have the function work only for matrices for which a <code class="highlighter-rouge">.ring</code> attribute has been added manually by the user. For example,</p>
<div class="highlighter-rouge"><pre class="highlight"><code>>>> from sympy.polys.solvers import RawMatrix as Matrix
>>> from sympy.polys.domains import ZZ
>>> m = Matrix([0,1,3],[2,4,1])
>>> setattr(m, "ring", ZZ)
</code></pre>
</div>
<p>Hopefully, at some point in the future matrices will have this attribute by default.</p>
<p>The Smith Normal Form was necessary to analyse the structure of the abelianisation of a group: abelian groups are modules over integers which is a PID and so the Smith Normal form is applicable if the relators of the abelianisation are written in the form of a matrix. If 0 is one of the abelian invariants (the diagonal entries of the Smith Normal form), then the abelianisation is infinite and so must be the whole group. I’ve added this test to the <code class="highlighter-rouge">.order()</code> method for <code class="highlighter-rouge">FpGroup</code>s and now it is able to terminate with the answer <code class="highlighter-rouge">oo</code> (infinity) for certain groups for which it wouldn’t terminate previously. I hope to extend this further with another way to evaluate the order: trying to find a finite index cyclic subgroup (this can be achieved by generating a random word in the group and considering the coset table corresponging to it), and obtain the order of the group by multiplying the index with the order of the cyclic subgroup. The latter could be infinite, in which case the whole group is. Of course, this might not always terminate, but it will terminate in more cases than coset enumeration applied directly to the whole group. This is also what’s done in <a href="https://www.gap-system.org">GAP</a>.</p>
<p>I have begun working on it but this week is the last before my exams, and I feel that I should spend more time revising. For this reason, I probably wouldn’t be able to send a PR with this new test by the end of the week. However, it would most likely be ready by the end of the next one, and considering that the only other thing I planned to do until the first evaluation period was to write (the main parts of) the <code class="highlighter-rouge">GroupHomomorphism</code> class assuming that the things it depends on (e.g. rewriting systems) are already implemented, I believe I am going to stay on schedule.</p>
The start2017-05-29T00:00:00+00:00http://valglad.github.io/2017/05/29/start<p>GSoC officially starts tomorrow but I’ve already begun working on my project because of exams later in June. So far everything is going according to plan. I’ve implemented the <code class="highlighter-rouge">subgroup()</code> method for <code class="highlighter-rouge">PermutationGroup</code>s and <code class="highlighter-rouge">FpGroup</code>s as well as <code class="highlighter-rouge">is_subgroup()</code> for <code class="highlighter-rouge">FpGroup</code>s. That was straight-forward except this one moment where I wanted to avoid creating a new instance of <code class="highlighter-rouge">FreeGroup</code> and rewriting the relators returned by <code class="highlighter-rouge">reidemeister_presentation()</code> in terms of this new instance because it seemed inelegant. I spend quite a while trying to come up with a better way and even started thinking of reimplementing the <code class="highlighter-rouge">FreeGroup</code> class but after a discussion with one of my mentors on SymPy’s <a href="https://gitter.im/sympy/GroupTheory">Group Theory channel</a> decided to create a new instance after all. It shouldn’t affect the performance too much anyway and reimplementing a whole class would be quite extreme.</p>
<p>Then I looked into improving the techniques for simplifying the presentation of subgroups. I hadn’t been sure about whether there would be much to do but actually I found that the code had quite a few redundant bits and there were some more serious potential problems with it, like a loop that deleted elements of the list over which it iterated. I ended up rewriting it to be more readable and making sure the list of relators is traversed properly. Additionally, the <code class="highlighter-rouge">reidemeister_presentation()</code> code used to apply the simplification techniques 20 times in a for loop which in some cases would be excessive and in others not enough - I replaced it with a while loop so that the representaion is simplified until no further improvement is achieved.</p>
<p>While I was at it, I found myself modifying some of the <code class="highlighter-rouge">FreeGroupElement</code> methods either to extend their functionality or because I noticed that their implementation would lead to bugs in some special cases. I also added a couple of new methods for manipulation of group words. Intuitively, <code class="highlighter-rouge">FreeGroupElement</code> words are just symbolic expressions on non-commutative (in the general case) symbols that only admit integer powers. But their implementation in SymPy is different from the regular symbolic expressions which are instances of the <code class="highlighter-rouge">Expr</code> class. As a result, the <code class="highlighter-rouge">Expr</code> methods, e.g. <code class="highlighter-rouge">subs()</code> or <code class="highlighter-rouge">simplify()</code> can’t be used with them directly (though of course, theoretically, one could build an equivalent symbolic expression out of a <code class="highlighter-rouge">FreeGroupElement</code>, apply the desired <code class="highlighter-rouge">Expr</code> method, make sure no fractional powers appear and go back) so equivalent methods have to be written separately. I have extended the group word substitution to probably all (or at least most) cases one might need. Simplification, on the other hand, is still missing. That said, the <code class="highlighter-rouge">simplify()</code> method of the <code class="highlighter-rouge">Exrp</code> class doesn’t currently do much in terms of simplification of non-commutative expressions so it couldn’t be used anyway (perhaps, some other method would be appropriate but I’m not sure which). However, unlike instances of <code class="highlighter-rouge">Expr</code>, group elements only involve one binary operation so the problem is somewhat easier (conceptually). The only real simplification one can make is finding powers of subwords and collecting them into one thing. Say, if we have the word <code class="highlighter-rouge">x*y*x*y*x*y</code>, a simpler way to write it would be <code class="highlighter-rouge">(x*y)**3</code> and it would be good to have that done automatically. I might work on implementing that sort of thing somewhere along the way because then simplifications for <code class="highlighter-rouge">reidemeister_presentation()</code> can be improved even further, and the output relators will be more readable. Plus it’s just a nice feature to have, though at present I’m not sure about how exactly I would go about that efficiently and how to best store the simplification so that it doesn’t need to be done again.</p>
<p>The PRs I’ve sent so far are <a href="https://github.com/sympy/sympy/pull/12658">here</a> and <a href="https://github.com/sympy/sympy/pull/12681">here</a> and are currently still being reviewed.</p>
<p>The next thing I’m going to work on are a couple of methods that could be used to determine if a given <code class="highlighter-rouge">FpGroup</code> is infinite. The one I plan to do first is considering the abelianisation of the group, writing the relators in the form of an integer matrix and essentially finding its Smith Normal form. This will probably occupy me for the next week.</p>
The plan2017-05-12T00:00:00+00:00http://valglad.github.io/2017/05/12/plan<p>This blog will follow the progress of my GSoC 2017 project for SymPy. My primary goal is to implement group homomorphisms and set it up in such a way that certain finite presentation groups (implemented as an <code class="highlighter-rouge">FpGroup</code> class in SymPy) could be considered as permutation groups via an isomorphism. That would be good because SymPy already has many group-theoretic algorithms implemented for perm groups. To get this to work, I will also need to implement rewriting systems for <code class="highlighter-rouge">FpGroup</code>s. You can see my <a href="https://github.com/sympy/sympy/wiki/GSoC-2017-Application-Valeriia-Gladkova:-Group-Theory">application</a> for details.</p>
<p>This post is a revised timeline for the project. I am currently in the middle of a term at uni and I’m going to have exams at the end of it: that’s 12-21 June (with 3 exam-free days in that period). For that reason I won’t be fully productive until 21 June but I’ll do my best (and certainly will catch up afterwards). As such, I think I should do a bit of coding before 30 May. I’ll start with some functionality unrelated to homomorphisms, as explained in my application. My current plan until the end of the First Evaluation period (26-30 June) is as follows:</p>
<ul>
<li>
<p><strong>By 30 May:</strong> Add a <code class="highlighter-rouge">.subgroup()</code> method and a <code class="highlighter-rouge">.parent</code> attribute to <code class="highlighter-rouge">FpGroup</code>s and <code class="highlighter-rouge">PermutationGroup</code>s. Probably make some improvements in the Reidemeister-Schreier elimination techniques. Submit a PR.</p>
</li>
<li>
<p><strong>31 May - 11 June:</strong> Implement better checks for infinite <code class="highlighter-rouge">FpGroup</code>s. That will include the <code class="highlighter-rouge">abelian_invariants</code> function somewhere in the rings module (I’ll do it for integers unless there is an obvious way to make the same algorithm work for general rings) and a search for a finite cyclic subgroup (which might not terminate but it’s better to give it a try since if a group is infinite, this might works but <code class="highlighter-rouge">coset_enumeration</code> is unlikely to terminate). Create a PR by the end of it if it’s finished.</p>
</li>
<li>
<p><strong>12-25 June</strong> My exams start. I’ll start writing the <code class="highlighter-rouge">GroupHomomorphism</code> class and its functions with the assumption that rewriting systems and other things I might need are already implemented (which I will actually do later on). I’ll also start writing my evaluation at the end of this period.</p>
</li>
</ul>