Skip to content

Added enhancement for power series that allows access to the coefficients of specific terms #39480

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

Merged
merged 12 commits into from
Apr 29, 2025

Conversation

Noel-Roemmele
Copy link
Contributor

Fixes #39314. Adds an enhancement to power series that when given a tuple of values corresponding to the powers of the term gives you the coefficient for said term. Functionality is similar to how coefficients are retrieved for multivariable polynomials. Also added a test for the enhancement.

📝 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

@DaveWitteMorris
Copy link
Member

Thanks for the enhancement. I will set to positive review on Wednesday if there are no other comments and make ptestlong (or CI testing) does not uncover any problems.

However, I think the initial docstring can be clarified. Perhaps something like:

Return the coefficient of the monomial ``x1^e1 * x2^e2 * ... * xk^ek`` 
if ``n = (e_1, e2, ..., ek)`` is a tuple whose length is the number of variables 
``x1,x2,...,xk`` in the power series ring. 

Return the sum of the monomials of degree ``n`` if ``n`` is an integer.

Copy link

github-actions bot commented Feb 10, 2025

Documentation preview for this PR (built with commit d6e3515; changes) is ready! 🎉
This preview will update shortly after each push to this PR.

@DaveWitteMorris
Copy link
Member

Sorry, I thought I already told you this, but it's not in my comment above, so apparently not: you need to change :trac" to :issue: in line 698.

@mantepse
Copy link
Contributor

I'm a bit split on this solution, because it makes power series behave differently from everything else. Did you think about the possibility of a more generic solution?

It would be good to at least try to unify the interface for polynomials, power series and lazy power series.

@DaveWitteMorris
Copy link
Member

I think this is a clear improvement over the status quo. Not only do I agree with the statement on the original issue that "the absence of this core functionality for multivariate series is a clear deficiency...", but this change also makes multivariable power series behave more like polynomials, which is a step toward unification of the interfaces. I think the unification should be achieved by adding this functionality to the other classes, not by handicapping this one.

On the other hand, I don't see a good reason to have the single-integer interface. Should this be deprecated, and replaced with a homogeneous component method? For even more unification, the power series would need a homogeneous components method that returns a dictionary-like object that contains all the homogeneous components, but I don't know how that would work.

Would it be easy to add the functionality of this method to lazy power series? I don't know anything about them.

@Noel-Roemmele
Copy link
Contributor Author

Noel-Roemmele commented Feb 19, 2025

Added small fixes suggested by mantepse.

@DaveWitteMorris
Copy link
Member

I opened issue #39698 for adding the same functionality to LazyPowerSeries.

@user202729
Copy link
Contributor

If I work with combinatorial species, symmetric functions or multivariate power series, I would actually expect that passing the degree would give me the homogeneous degree component. In the end, that's the unfying feature of all these mathematical objects.

This is not true. For univariate power series and univariate polynomial, __getitem__ returns the coefficient.


On the other hand, I don't see a good reason to have the single-integer interface.

I suspect this was not too well-thought-out and just added to access the components of the object (because the is internally implemented as follows

The implementation of the multivariate power series ring uses a combination
of multivariate polynomials and univariate power series. Namely, in order
to construct the multivariate power series ring `R[[x_1, x_2, \cdots, x_n]]`,
we consider the univariate power series ring `S[[T]]` over the multivariate
polynomial ring `S := R[x_1, x_2, \cdots, x_n]`, and in it we take the
subring formed by all power series whose `i`-th coefficient has degree `i`
for all `i \geq 0`. This subring is isomorphic to
`R[[x_1, x_2, \cdots, x_n]]`. This is how `R[[x_1, x_2, \cdots, x_n]]` is
implemented in this class. The ring `S` is called the foreground polynomial
ring, and the ring `S[[T]]` is called the background univariate power
series ring.

)


For what it's worth singular multivariate polynomial ring already support this. But they also support single integer (return the coefficient, not the polynomial).

sage: R.<x,y> = QQ[]
sage: (x*y)[1, 1]
1

They also have monomial_coefficient method and coefficient method. On the other hand graded modular form element has homogeneous_component method that returns the "polynomial", not just the "coefficient". (in modular form case, it is hard to tell what a coefficient is.)


That said, I think it's a bad idea to have different behavior for f[1] and f[1,]. Since it seems clear that making __getitem__ returns coefficient in base ring is preferred (also consistent with univariate polynomial ring and multivariate polynomial ring), I suggest

  • for now: implement homogeneous_component for multivariate polynomial ring, and deprecate __getitem__(self, ⟨integer⟩), telling user to use homogeneous_component instead;
  • one year later, change __getitem__(self, ⟨integer⟩) to treat it like an one-element tuple.

this PR doesn't conflict with that goal, so it's fine.

@mantepse
Copy link
Contributor

Sorry, I had no time, but I am quite concerned about the general strategy. Is this urgent to go in?

@user202729
Copy link
Contributor

Sorry, I had no time, but I am quite concerned about the general strategy. Is this urgent to go in?

Not sure what you mean — do you agree with my proposal of general strategy described above? If yes then this can be merged just fine.

Or do you think having f[1] and f[1,] being temporarily different is problematic?

@mantepse
Copy link
Contributor

If I work with combinatorial species, symmetric functions or multivariate power series, I would actually expect that passing the degree would give me the homogeneous degree component. In the end, that's the unfying feature of all these mathematical objects.

This is not true. For univariate power series and univariate polynomial, __getitem__ returns the coefficient.

Sorry, I miscommunicated and additionally made a mistake by not distinguishing between homogeneous component and coefficient in the univariate case. I was focussed on the problem that, at least for $\mathbb N$-graded objects, getting the homogenous piece of given degree is rather important.

I am very unsure whether it is a good idea to make, say, homogeneous_component be the only method to get a part of given degree. It feels very natural to me to have

sage: L.<x,y> = LazyPowerSeriesRing(QQ)
sage: (1/(1-x-y))[3]
x^3 + 3*x^2*y + 3*x*y^2 + y^3

It doesn't seem completely inconsistent to me to return a coefficient in the univariate case - in my mind I identify sequences with formal power series. But I am very unsure here, too. @tscrim, what do you think?

I somewhat doubt that it is realistic to have gradings other than the $\mathbb N` grading here.

If the parent is a CombinatorialFreeModule, passing an element of the index set to the __getitem__ method currently yields a coefficient, and 0 otherwise, even if the element is of the wrong type. I think that's a bad idea.

sage: s = SymmetricFunctions(QQ).s()
sage: e = s[2,1,1]
sage: e[2,1,1]
0
sage: e[Partition([2,1,1])]
1

@user202729
Copy link
Contributor

I am very unsure whether it is a good idea to make, say, homogeneous_component be the only method to get a part of given degree.

For consistency of API, it's either that or adding a specialized method like coefficient_at_tuple (there's none as far as I can tell) to get the coefficient in the base ring. Currently there is no method that returns x^2 from x^2+2*x+3 by specifying the homogeneous degree 2 either, so using __getitem__ for coefficient in base ring and homogeneous_component for component in polynomial ring (or equivalent) seems the most natural to me.

I somewhat doubt that it is realistic to have gradings other than the $\mathbb N$ grading here.

Actually some types of weighted grading is already implemented. (to some extent, see #37155 )

If the parent is a CombinatorialFreeModule, passing an element of the index set to the __getitem__ method currently yields a coefficient, and 0 otherwise, even if the element is of the wrong type. I think that's a bad idea.

Okay, this is just a technical issue and can be fixed by checking isinstance(…, (tuple, list)) and raise TypeError or something similar?

@tscrim
Copy link
Collaborator

tscrim commented Mar 17, 2025

I think it is fully consistent to return a coefficient in the univariate case and a polynomial in the multivariate case. It is about decomposing the vector space into its graded components. So in this sense, the API is uniform. (Note: Polynomials are not considered as graded objects for morphism reasons, but otherwise we treat them as $\mathbb{N}^k$ graded for $k$ variables.)

For the power series rings, the grading on the polynomial rings is important because we use that to define the valuation, which then gives the completion. In particular, here we only consider the total degree.

For power series rings, we could make both accessible by differentiating a tuple versus integer input. However, this will not be possible when working with a completion in general as the both could be indexed by $\mathbb{N}$ with each component isomorphic to the base field. Now, you could argue that in such a completion it should return the coefficient, but then we have to really know something about the input that is likely impossible to determine without burdening the user.

@user202729
Copy link
Contributor

It is about decomposing the vector space into its graded components.

On the other hand there is more structure in the ring of polynomials than a vector space, for example you can multiply two coefficients together.

Anyway, what do you think MPowerSeriesRing's (or MPolynomialRing) behavior should be when only one variable is provided?

@tscrim
Copy link
Collaborator

tscrim commented Mar 17, 2025

Okay, an algebra into its graded components, but that is only an isomorphism of vector spaces anyways.

The most consistent thing to me would be for a "fake" multivariate 1 variable power series input for an integer to return the homogeneous component. E.g., for f = x^2, then f[2] returns x^2. This would be consistent with thinking of $k[x] = \bigoplus_m k[k]_m$ (the $m$-th graded component) instead of $k[x] = \bigoplus_m k$ for the univariate case.

It's a slightly annoying difference, yes, but the model we are using does matter.

@user202729
Copy link
Contributor

@mantepse Do you think the current explanation is good? So you can still have f[1] = f.homogeneous_component(1), but then f[1] ≠ f[1,] if you use 1-variable multivariate implementation (which I think is probably fine as long as there's plenty of warning in the documentation)

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.

Well, perhaps we can get this in right now. @mantepse If you object (e.g., need more time to consider stuff), feel free to revert.

A nice while-we-are-at-it thing would be making the error message begin with a lower case letter and without a period/full-stop at the end to be consistent with Python's error message style. If you want to do this here, please go ahead and do it; you can reset the positive review after. Otherwise, it can be handled separately.

@vbraun vbraun merged commit e7eabc4 into sagemath:develop Apr 29, 2025
17 of 20 checks passed
@Noel-Roemmele Noel-Roemmele deleted the 39314CoefficientPowerSeries branch May 2, 2025 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unable to extract a particular coefficient of a multivariate power series
6 participants