Skip to content

Conversation

trevorkarn
Copy link
Contributor

@trevorkarn trevorkarn commented Apr 28, 2023

📚 Description

The behavior of Partitions(n, starting=mu) is confusing. It iterates over partitions starting with mu, but it is not required that mu be a partition of n. For example:

sage: P = Partitions(5, starting=[3,1]); print(P); list(P)
Partitions of the integer 5 starting with [3, 1]
[[3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]

These are partitions of 4 not of 5. The change is to add a ValueError in Partitions_starting to assert that n
must agree with the weight of mu.

The example above was drawn from the tests, so a few tests are changed so that they now pass.

📝 Checklist

  • The title is concise, informative, and self-explanatory.
  • The description explains in detail what this PR is about.
  • I have linked a relevant issue or discussion.
  • I have created tests covering the changes.
  • I have updated the documentation accordingly.

⌛ Dependencies

@tscrim
Copy link
Collaborator

tscrim commented Apr 29, 2023

I don't think this is the correct fix as the input is valid. It should either:

  1. Be the empty set (so the __iter__ simply returns).
  2. Iterate starting from the lex min less than the given partition.

I am leaning towards (1) as it is easier to implement and most people only intend to compare partitions of the same size. However, (2) fits with what the doc says and lex order makes sense for all partitions (which is useful to do sometimes).

@trevorkarn
Copy link
Contributor Author

  1. Be the empty set (so the __iter__ simply returns).
  2. Iterate starting from the lex min less than the given partition.

I am leaning towards (1) as it is easier to implement and most people only intend to compare partitions of the same size. However, (2) fits with what the doc says and lex order makes sense for all partitions (which is useful to do sometimes).

It looks like (2) is in keeping with what the ending kwarg does.

sage: Partitions(4, ending=[2,1])
Partitions of the integer 4 ending with [2, 1]
sage: list(_)
[[4], [3, 1], [2, 2], [2, 1, 1]]

For consistency's sake, I'll do (2).

@trevorkarn
Copy link
Contributor Author

Another bug with the current approach:

sage: P = Partitions(5, starting=[3,1]); print(P); list(P)
Partitions of the integer 5 starting with [3, 1]
[[3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
sage: Partition([3,1]) in P
False

@tscrim
Copy link
Collaborator

tscrim commented May 2, 2023

Indeed, it seems like we should go with (2); good find.

@trevorkarn
Copy link
Contributor Author

Indeed, it seems like we should go with (2); good find.

It wasn't too bad to fix - I just had to change the Partitions_starting.first method.

@trevorkarn
Copy link
Contributor Author

Actually I think there is still a logical mistake I'm making. It only makes sense to have starting be too big. So if starting is too small I should implement option (1), and if it is too big option (2).

For example, [2,1,1] is not less than [2,1] because 2 <= 2, 1<= 1, 1 >= 0. But the last comment I pushed wouldn't catch that (I went back to add a test and it failed in _contains_ for exactly this reason).

@tscrim
Copy link
Collaborator

tscrim commented May 8, 2023

Right. I believe you can just add the trailing 1s, then return the next partition in lex order as the starting partition.

@trevorkarn
Copy link
Contributor Author

Right. I believe you can just add the trailing 1s, then return the next partition in lex order as the starting partition.

Ah right that makes sense. I think its good now. I did also notice the following issue:

sage: P = Partitions(4, ending = [5])
sage: P.list()
[[4]]
sage: Partition([4]) in P
False

I think this should be an empty list. I think I can fix it by adding an __iter__ method to Partitions_ending (mirroring the fix I did for Partitions_starting). Should I do that on this issue/PR, or another one?

@tscrim
Copy link
Collaborator

tscrim commented May 9, 2023

You shouldn't need the __iter__ method at all. Python(?) automagically uses first() and next() to build an iterator. I would just change the next() to be part <= self._ending and have a check in first of something like

if self._ending and self.n <= self._ending[0] and not (self.n == self._ending[0] and len(self._ending) == 1):
    return None

Although it is up to you if you want do it here or on a separate PR.

@trevorkarn
Copy link
Contributor Author

You shouldn't need the __iter__ method at all. Python(?) automagically uses first() and next() to build an iterator. I would just change the next() to be part <= self._ending and have a check in first of something like

if self._ending and self.n <= self._ending[0] and not (self.n == self._ending[0] and len(self._ending) == 1):
    return None

Although it is up to you if you want do it here or on a separate PR.

When I try to do that, I get the following test failing:

Failed example:
    Partitions(4, ending=[5]).list()
Expected:
    []
Got:
    [None]

I had the same issue with the Partitions_starting and adding __iter__ was able to fix it. Is that the wrong fix for Partitions_starting too?

@tscrim
Copy link
Collaborator

tscrim commented May 10, 2023

Ah, we just need to make a small additional modification to EnumeratesSets.ParentMethods._iterator_from_next()

f = self.first()
while not (f is None or f is False):
    yield f
    try:
        f = self.next(f)
    except (TypeError, ValueError):
        f = None

I also cleaned up the implementation a bit. Now if first() returns None, then it will create an empty list.

@trevorkarn
Copy link
Contributor Author

Ah, we just need to make a small additional modification to EnumeratesSets.ParentMethods._iterator_from_next()

f = self.first()
while not (f is None or f is False):
    yield f
    try:
        f = self.next(f)
    except (TypeError, ValueError):
        f = None

I also cleaned up the implementation a bit. Now if first() returns None, then it will create an empty list.

Ah awesome thanks. Changes are made and ready for review.

Copy link
Collaborator

@tscrim tscrim left a comment

Choose a reason for hiding this comment

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

Thanks. Just two last little details.

@github-actions
Copy link

Documentation preview for this PR is ready! 🎉
Built with commit: 4ec3ad4

Copy link
Collaborator

@tscrim tscrim left a comment

Choose a reason for hiding this comment

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

Thank you. LGTM.

@vbraun vbraun merged commit a62543d into sagemath:develop May 28, 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.

4 participants