Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added kth roots to Permutation #35053

Merged
merged 22 commits into from
Nov 5, 2023

Conversation

GermainPoullot
Copy link
Contributor

📚 Description

Added 3 functions that deal with k-th roots of permutations:

  1. Permutation.kth_roots(k) compute a iterator of over all k-th roots of self.
  2. Permutation.has_kth_root(k) determines if self has a k-th root (or several).
  3. Permutation.number_of_kth_roots(k) returns the number of k-th roots of self.

Added integer_partition_with_given_parts(n, parts) in partition.py (for use in k-th roots computations):
it creates a iterator over all partitions of n which parts are in the variable parts.

📝 Checklist

  • I have made sure that the title is self-explanatory and the description concisely explains the PR.
  • I have linked an issue or discussion.
  • I have created tests covering the changes.
  • I have updated the documentation accordingly.

⌛ Dependencies

Added integer_partition_with_given_parts in partition.py (for use in kth roots computations).
@codecov-commenter
Copy link

codecov-commenter commented Feb 10, 2023

Codecov Report

Base: 88.60% // Head: 88.59% // Decreases project coverage by -0.02% ⚠️

Coverage data is based on head (bbe11ba) compared to base (698001b).
Patch coverage: 100.00% of modified lines in pull request are covered.

❗ Current head bbe11ba differs from pull request most recent head 99973a5. Consider uploading reports for the commit 99973a5 to get more accurate results

Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #35053      +/-   ##
===========================================
- Coverage    88.60%   88.59%   -0.02%     
===========================================
  Files         2136     2136              
  Lines       396141   396267     +126     
===========================================
+ Hits        351009   351070      +61     
- Misses       45132    45197      +65     
Impacted Files Coverage Δ
src/sage/combinat/partition.py 96.91% <100.00%> (+0.02%) ⬆️
src/sage/combinat/permutation.py 96.98% <100.00%> (+0.33%) ⬆️
src/sage/interfaces/qsieve.py 71.30% <0.00%> (-2.61%) ⬇️
src/sage/doctest/forker.py 80.24% <0.00%> (-1.75%) ⬇️
src/sage/modular/local_comp/liftings.py 98.33% <0.00%> (-1.67%) ⬇️
src/sage/cpython/_py2_random.py 74.79% <0.00%> (-1.66%) ⬇️
src/sage/schemes/elliptic_curves/hom_frobenius.py 96.34% <0.00%> (-1.22%) ⬇️
src/sage/schemes/elliptic_curves/hom_velusqrt.py 94.09% <0.00%> (-1.19%) ⬇️
src/sage/interfaces/ecm.py 92.48% <0.00%> (-1.16%) ⬇️
src/sage/combinat/posets/poset_examples.py 87.67% <0.00%> (-1.15%) ⬇️
... and 25 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@mantepse
Copy link
Collaborator

  • Integer partitions with given parts already exists:
sage: list(Partitions(10, parts_in=[2,3,5]))
[[5, 5], [5, 3, 2], [3, 3, 2, 2], [2, 2, 2, 2, 2]]
  • I think Permutation.roots would be easier to discover.
  • The number of k-th roots only depends on the cycle type of the partition. This should be stated in the docstring - but perhaps, the method should in fact be a method of Partition? I am not sure about this. You may also want to compare with https://www.findstat.org/StatisticsDatabase/St000811.

@mantepse mantepse self-requested a review February 10, 2023 10:48
@mantepse
Copy link
Collaborator

Further minor things:

  • indexes should be indices
  • @fchapoton, there seems to be something wrong with the linter checks: there is almost never a whitespace after the comma.

@GermainPoullot
Copy link
Contributor Author

  • Integer partitions with given parts already exists:

Indeed! Thanks. How did I miss that...
I deleted my function and used this one instead.

* I think `Permutation.roots` would be easier to discover.

I agree (especially because .kth_roots() compute by default the square roots), but if someone wants to extend this to Weyl groups or Coxeter groups, "roots" would feel weird I think.

* The number of k-th roots only depends on the cycle type of the partition.

You're right. Even thought I think "number_of_kth_roots" is better fit in this module, with its sibblings. I've added the info in doc.

(Changed the name of indices and added spaces after coma.)

@mantepse
Copy link
Collaborator

@fchapoton, did you see my comment? I think it is important, because this might create a huge mess in the near future.

@mantepse
Copy link
Collaborator

  • I think Permutation.roots would be easier to discover.

I agree (especially because .kth_roots() compute by default the square roots), but if someone wants to extend this to Weyl groups or Coxeter groups, "roots" would feel weird I think.

Excellent point. I still hope for a better name, but maybe there is none.

  • The number of k-th roots only depends on the cycle type of the partition.

You're right. Even thought I think "number_of_kth_roots" is better fit in this module, with its sibblings. I've added the info in doc.

  • to get the dict of multiplicities of cycle lengths, you can use pi.cycle_type().to_exp_dict()
  • I have not checked your algorithm, but if you need key and value of a dict (as in Cycles), you should iterate over Cycles.items().
  • the inner loop can be replaced by prod(factorial(x-1) * m**(x-1) for x in partition), which is much easier to read.
  • I don't see why you first collect the counts into a dict and then take the product.
  • variable names should follow the style in https://doc.sagemath.org/html/en/developer/coding_basics.html#python-code-style, in particular https://peps.python.org/pep-0008/
  • please remove partitions.py from the diff

@tscrim
Copy link
Collaborator

tscrim commented Feb 11, 2023

I feel we should call this nth_roots() to match what, e.g., field elements do (they have a nth_root() method). Although calling it roots() is probably the most natural, but as mentioned, it directly conflicts with Coxeter group notions.

There should not be a default for k. (What makes 2 so special anyways?)

Remove also the change (removing a line) to partition.py.

Add tests for corner cases of n=0,1.

Make sure pyflakes is run. I think P = Permutations(self.size()) is unused in the number_of_kth_roots.


Some ways you can get more performance:

itertools is also a great friend.

This whole part seems to be creating a lot of unnecessary objects:

            b = False
            for partition in Partitions(N, parts_in=parts):
                b = True
                count = SetPartitions(N, partition).cardinality()
                for x in partition:
                    count *= factorial(x-1) * m**(x-1)
                Counts[m] += count
            if not b:
                return 0

I would refactor out the cardinality method into a standalone function. Likewise, you can just use the Partitions(N, parts_in=parts)._other_iterator(), which yields lists. Then with a slight modification, the cardinality() could handle input as a list (instead of a Partition) by avoiding to_exp_dict() and just count the multiplicities directly.

Change kth to nth
Improve number_of_nth_roots (better way to iter and more readable)
Idem for has_nth_root
Minor improvements in nth_roots
Copy link
Collaborator

@mantepse mantepse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is beginning to look very good!


A k-th root of the permutation self is a permutation Gamma such that Gamma^k == self.
A n-th root of the permutation ``self`` is a permutation `\gamma` such that `\gamma^n == self`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is now An n-th root :-)

INPUT:

- k -- optional integer (default 2), at least 1
Note that the number of n-th roots only depend on the cyclic type of ``self``.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is cycle type, rather than cyclic type.

Copy link
Contributor Author

@GermainPoullot GermainPoullot Feb 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. I'm confused by the French notation.

src/sage/combinat/permutation.py Outdated Show resolved Hide resolved
@@ -5322,7 +5325,7 @@ def kth_roots(self, k=2):

def merging_cycles(list_of_cycles):
"""
Generate all l-cycles such that its k-th power is the product of cycles in Cycles (which conctains gcd(l, k) cycles of lenght l/gcd(l, k))
Generate all l-cycles such that its n-th power is the product of cycles in Cycles (which conctains gcd(l, n) cycles of lenght l/gcd(l, n))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring is a bit unclear. In particular, what is Cycles?

src/sage/combinat/permutation.py Outdated Show resolved Hide resolved
"""
M = [0 for _ in L]
m = len(M)
for j in range(m):
M[(j*k)%m] = L[j]
M[(j*n)%m] = L[j]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linter will require this to be written as M[(j * k) % m].

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. Plus PEP8 says we can put higher precedence operators without spaces (and [] counts as an operator). I don't think the linter is (nor should be) that strict.

@@ -5362,18 +5365,19 @@ def rewind(L, k):
Cycles[lc] = []
Cycles[lc].append(c)

# for each length m, collects all product of cycles which k-th power gives the product prod(Cycles[l])
# for each length m, collects all product of cycles which n-th power gives the product prod(Cycles[l])
Possibilities = {m: [] for m in Cycles}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need a dict here, since you prepare the entries for each cycle separately. Also, variable names are usually lowercase.

for m, N in Cycles.items():
N = Integer(N) # I don't know why but ._findfirst doesn't work without
parts = [x for x in divisors(n) if gcd(m*x, n) == x]
if not Partitions(0, parts_in=[])._findfirst(N, parts):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really strange line of code. Partitions(0, parts_in=[]) is simply the empty partition. _findfirst is a method without documentation, what is it suppose to do?

Copy link
Contributor Author

@GermainPoullot GermainPoullot Feb 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My goal here is just to know if there exists a partition of N with parts in parts. I haven't been able to find an efficient method to do it.
Here, I create a parent Partitions_parts_in (writing Partitions_parts_in(N, parts) does not seem to work), and then ask for the first element.
._findfirst is the method that the class Partitions_parts_in uses to iterate over the partitions, if i understand well.
If you have a better idea, I'll take it!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partitions(N, parts_in=parts).is_empty()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

P = Permutations(self.size())
Cycles = self.cycle_type().to_exp_dict()
Result = 1
for m, N in Cycles.items():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be helpful to rename m to length and N to multiplicity, or perhaps m. Also, d might be a good name for a divisor, instead of x.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

N is not a multiplicity, it is the number of cycles of a given length.
I've changed the others.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, multiplicty of the cycle length

Result = 1
for m, N in Cycles.items():
parts = [x for x in divisors(n) if gcd(m*x, n) == x]
Result *= sum(SetPartitions(N, pa).cardinality() *
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be helpful to explain this computation in a comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and not use caml case for variable names, ie Cycles -> cycles, Result -> result. Caml case is reserved for class names.

@mantepse
Copy link
Collaborator

I'd like to mention that I would first like to have this code be readable, and then check whether it performs well.

@mantepse
Copy link
Collaborator

ping?

@fchapoton
Copy link
Contributor

Courage, Germain ! Ca demande une bonne dose de ténacité, mais tu as la chance d'avoir trouvé un rapporteur. Si tu n'es pas disponible, tu peux lui dire quand tu le seras.

@tscrim
Copy link
Collaborator

tscrim commented Mar 28, 2023

@GermainPoullot ping?

@fchapoton
Copy link
Contributor

I have updated the branch by merging the latest beta. This is to allow the checks to be run again.

remove some spaces in empty lines
@fchapoton fchapoton self-assigned this Oct 30, 2023
@fchapoton
Copy link
Contributor

I have once more updated the branch by merging the latest beta. This is to allow the checks to be run again.

variables en minuscules
less whitespace
@fchapoton
Copy link
Contributor

I am afraid I have broken some things when doing my changes..

@fchapoton
Copy link
Contributor

I have fixed things and doctests now pass.

suggested details
@mantepse
Copy link
Collaborator

Thank you for doing this! I think this is ready to go, as soon as the bot has finished!

@mantepse
Copy link
Collaborator

just a typo: list(sigma.nth_roots(1)) == [Sigma]

r"""
Decide if ``self`` has n-th roots.

An n-th root of the permutation ``self`` is a permutation `\gamma` such that `\gamma^n == self`.
Copy link
Collaborator

@mantepse mantepse Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\gamma^n == self doesn't come out properly in the documentation. Not sure what it should be, possibly

``gamma`` such that ``gamma^n == self``

or

of the permutation `\sigma` is a permutation `\gamma` such that `\gamma^n = \sigma`.

I don't know how to do it properly.

The same comment applies to the docstrings of n_th_roots and number_of_nth_roots.

I'm sorry :-(

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

of the permutation `\sigma` is a permutation `\gamma` such that `\gamma^n = \sigma`.

This is the one I would do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done already

@mantepse
Copy link
Collaborator

LGTM

Copy link
Collaborator

@mantepse mantepse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thank you!

Copy link

Documentation preview for this PR (built with commit 13b52c5; changes) is ready! 🎉

vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 1, 2023
    
### 📚 Description

Added 3 functions that deal with k-th roots of permutations:
1) Permutation.kth_roots(k) compute a iterator of over all k-th roots of
self.
2) Permutation.has_kth_root(k) determines if self has a k-th root (or
several).
3) Permutation.number_of_kth_roots(k) returns the number of k-th roots
of self.

Added integer_partition_with_given_parts(n, parts) in partition.py (for
use in k-th roots computations):
it creates a iterator over all partitions of n which parts are in the
variable parts.

<!-- ^^^^^
Please provide a concise, informative and self-explanatory title.
Don't put issue numbers in there, do this in the PR body below.
For example, instead of "Fixes sagemath#1234" use "Introduce new method to
calculate 1+1"
-->


<!-- Describe your changes here in detail -->
<!-- Why is this change required? What problem does it solve? -->
<!-- If it resolves an open issue, please link to the issue here. For
example "Closes sagemath#1337" -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [x] I have made sure that the title is self-explanatory and the
description concisely explains the PR.
- [ ] I have linked an issue or discussion.
- [x] I have created tests covering the changes.
- [x] I have updated the documentation accordingly.

### ⌛ Dependencies
<!-- List all open pull requests that this PR logically depends on -->
<!--
- #xyz: short description why this is a dependency
- #abc: ...
-->
    
URL: sagemath#35053
Reported by: GermainPoullot
Reviewer(s): Frédéric Chapoton, GermainPoullot, Martin Rubey, Travis Scrimshaw, Vincent Delecroix
vbraun pushed a commit to vbraun/sage that referenced this pull request Nov 2, 2023
    
### 📚 Description

Added 3 functions that deal with k-th roots of permutations:
1) Permutation.kth_roots(k) compute a iterator of over all k-th roots of
self.
2) Permutation.has_kth_root(k) determines if self has a k-th root (or
several).
3) Permutation.number_of_kth_roots(k) returns the number of k-th roots
of self.

Added integer_partition_with_given_parts(n, parts) in partition.py (for
use in k-th roots computations):
it creates a iterator over all partitions of n which parts are in the
variable parts.

<!-- ^^^^^
Please provide a concise, informative and self-explanatory title.
Don't put issue numbers in there, do this in the PR body below.
For example, instead of "Fixes sagemath#1234" use "Introduce new method to
calculate 1+1"
-->


<!-- Describe your changes here in detail -->
<!-- Why is this change required? What problem does it solve? -->
<!-- If it resolves an open issue, please link to the issue here. For
example "Closes sagemath#1337" -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [x] I have made sure that the title is self-explanatory and the
description concisely explains the PR.
- [ ] I have linked an issue or discussion.
- [x] I have created tests covering the changes.
- [x] I have updated the documentation accordingly.

### ⌛ Dependencies
<!-- List all open pull requests that this PR logically depends on -->
<!--
- #xyz: short description why this is a dependency
- #abc: ...
-->
    
URL: sagemath#35053
Reported by: GermainPoullot
Reviewer(s): Frédéric Chapoton, GermainPoullot, Martin Rubey, Travis Scrimshaw, Vincent Delecroix
@vbraun vbraun merged commit 16dadc9 into sagemath:develop Nov 5, 2023
16 of 22 checks passed
@mkoeppe mkoeppe added this to the sage-10.2 milestone Nov 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants