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

Implement basic multivariate polynomial species #38446

Draft
wants to merge 111 commits into
base: develop
Choose a base branch
from

Conversation

Newtech66
Copy link
Contributor

Related to #30727.

We implement basic functionality for multivariate polynomial species, using its representation as a pair of a permutation group and a mapping between the domain of the permutation group and some variables. We provide addition, multiplication, and (partitional) composition (for some special cases). We also allow it to be constructed as a group action (or a sequence thereof). Atomic and molecular decompositions are automatically computed thanks to #38371.

📝 Checklist

  • The title is concise and informative.
  • 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 and checked the documentation preview.

⌛ Dependencies

Dependent on #37991 (presently, may change soon).

Newtech66 and others added 30 commits May 12, 2024 19:59
…groups

Also added various miscellaneous functions
Also some fixes to _element_constructor_ ConjugacyClassesOfSubgroups
Added _repr_ for ConjugacyClassesOfSubgroups
I now output B[(gens or name if available)] as _repr_ for generators, for example B[1] + 2*B[(2,3,4)]
@Newtech66
Copy link
Contributor Author

Here is a small glitch - in a fresh session:

sage: G = PermutationGroup([[], [(1,2),(3,4)]])
sage: P = PolynomialSpecies(ZZ, ["X"])
sage: P(G)
{((), (1,2)(3,4)): ({1, 2, 3, 4})}

The useless identity generator should be canonicalized away.

Done, now ConjugacyClassOf... _canonicalize uses gens_small.

src/sage/rings/species.py Outdated Show resolved Hide resolved
sage: E2XY = At(G, pi)
sage: At(G, pi).rename("E_2(XY)"); E2XY
E_2(XY)
sage: m = P._indices.gen((G, pi)); m
Copy link
Collaborator

Choose a reason for hiding this comment

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

This looks a bit fishy to me: why should gen accept anything but an atomic species? It seems to me that only _element_constructor_ should accept input that is not in the right form.

I think you could remove gen, and make _project return an atomic species, no?

I now see that you then get an infinite recursion because of the group computation - can you remind me why it is better to compute the group always, rather than only when it is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My intention originally was to only compute the group when needed. It appears that I may have instead achieved the opposite, because I was trying to cache intermediate results for optimisation 🤔 ...

@mantepse
Copy link
Collaborator

Would be nice to have quick access to the group representation of a molecular species...perhaps as a lazy attribute? But I don't see a nice way to do it. I need it for composition, because it's much easier if I am given the groups for two molecular species, instead of having to manually construct it from the corresponding atomic decomposition first.

I just found this comment. I think it is best to make it a cached method of MolecularSpecies.Element like

@cached_method
def group(self):

and compute it there.

@mantepse
Copy link
Collaborator

Let me ask another question concerning canonicalization: why does AtomicSpecies inherit from ElementCache?

It seems to me that given the "canonical" representative (in ConjugacyClassesOfDirectlyIndecomposableSubgroups._cache), the domain partition determines the species completely, and two atomic species are equal if and only if the "canonical" representatives and the domain partitions are equal. No?

@Newtech66
Copy link
Contributor Author

So, how do we store the name associations? And yes, given the canonical representative, the domain partition is enough.

@mantepse
Copy link
Collaborator

So, how do we store the name associations?
And yes, given the canonical representative, the domain partition is enough.

I see, in principle, two ways to do this:

  1. make AtomicSpecies._element_constructor_ return identical objects (rather than objects which are only equal) - not sure how to do this, though
  2. make AtomicSpeciesElement inherit from UniqueRepresentation.

I could only find one example of an element class that inherits from UniqueRepresentation, which is FormsRingElement in graded_ring_element.py. I don't know why. @tscrim, is doing this a bad idea?

src/sage/rings/species.py Outdated Show resolved Hide resolved
src/sage/rings/species.py Outdated Show resolved Hide resolved
@mantepse
Copy link
Collaborator

Here is an important bug which is possibly related to the missing total order:

sage: P = PolynomialSpecies(QQ, "X")
sage: X = P(SymmetricGroup(1))
sage: E2 = P(SymmetricGroup(2))
sage: (E2 + X^2).coefficients()
...
TypeError: '<' not supported between instances of 
'AtomicSpecies_with_category.element_class' and
'AtomicSpecies_with_category.element_class'

@Newtech66
Copy link
Contributor Author

How would we break ties between atomic species with equal multicardinality?


EXAMPLES::

sage: P = PolynomialSpecies(QQ, ["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.

E2(X^2) fails if we use P = PolynomialSpecies(ZZ, ["X"]) instead.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes. This is unfortunate, but a consequence of the way I implement call

ElementCache.__init__(self)
self._arity = indices._arity

def _project(self, G, pi, part):
Copy link
Collaborator

Choose a reason for hiding this comment

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

This does not depend on self currently. Maybe it should really be def _project(self, part)?

@mantepse
Copy link
Collaborator

@tscrim, I think this is now essentially ready for discussion. My main question is whether the ad-hoc ElementCache should be replaced by a UniqueRepresentation of the Element classes.

There is certainly a lot of room for improvement, but I am hoping that such would be of local kind.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants