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

Laurent polynomial/series modularization fixes #35554

Merged
merged 9 commits into from
Jun 3, 2023

Conversation

mkoeppe
Copy link
Contributor

@mkoeppe mkoeppe commented Apr 23, 2023

📚 Description

We remove several obstacles to modularization:

  • sage.data_structures.stream importing from sage.combinat.sf
  • eager module-level imports in sage.rings.bigoh, importing LaurentSeries, PuiseuxSeries, padics.
  • LaurentSeriesRing._element_constructor_ unconditionally importing sage.libs.pari.all just for an isinstance test
  • import of factorial from sage.functions (only the version from sage.arith is needed)
  • multivariate implementation of Laurent polynomials (with compile-time dependency on sage.matrix) mixed with the univariate implementation

Also adding # optional tags for the doctests that depend on sage.rings.finite_rings, sage.symbolic.

Part of:

📝 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

@mkoeppe mkoeppe force-pushed the laurent_modularization_fixes branch from 48d4ecf to eaef6e6 Compare April 23, 2023 23:12
@mkoeppe mkoeppe requested a review from mantepse April 23, 2023 23:12
@mantepse
Copy link
Collaborator

I think it would make much more sense to move symmetric functions to sage.algebras. It seems to me like a historic accident that they reside in sage.combinat.

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Apr 24, 2023

I think it would make much more sense to move symmetric functions to sage.algebras. It seems to me like a historic accident that they reside in sage.combinat.

That would be a plausible redesign. However, I'm using these feature tags in a looser way: Most of sage.algebras and sage.combinat will likely be shipped in the same distribution package, so use of "algebras whose bases are of combinatorial nature" could still be marked # optional - sage.combinat.

@kwankyu
Copy link
Collaborator

kwankyu commented Jun 2, 2023

You use two idioms

lazy_import('sage.rings.padics.padic_generic_element', 'pAdicGenericElement')

and

try:
    from .laurent_series_ring_element import LaurentSeries
except ImportError:
    LaurentSeries = ()  

to modify module level imports of classes, for modularization. How are they different in terms of usage?

sage: check(L, gen(), valuation=-5)
sage: L.<z> = LazyLaurentSeriesRing(GF(2)) # optional - sage.rings.finite_rings
sage: check(L, lambda n: n, valuation=-5) # optional - sage.rings.finite_rings
sage: check(L, gen(), valuation=-5) # optional - sage.rings.finite_rings

sage: L = LazyDirichletSeriesRing(QQbar, "s")
sage: check(L, lambda n: n, valuation=2)
sage: check(L, gen(), valuation=2)

Copy link
Collaborator

@kwankyu kwankyu Jun 2, 2023

Choose a reason for hiding this comment

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

sage.rings.number_field?

By the way, this being singular is not consistent with sage.rings.finite_rings being plural...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I'm also mildly annoyed by this inconsistency

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in b9bf5bb

sage: L.<x,y> = LaurentPolynomialRing(QQ) # indirect doctest
sage: x*y
sage: L.<x,y> = LaurentPolynomialRing(QQ) # indirect doctest # optional - sage.modules
sage: x*y # optional - sage.modules
x*y
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this (just constructing the ring and an element) depend on sage.modules? Then the distribution package that installs laurent_polynomial.pyx should install sage.modules. No?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

see below

False
sage: (2 + 4*u + 2*u^2).is_square()
sage: (2 + 4*u + 2*u^2).is_square() # optional - sage.rings.number_field
True
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm. So perhaps sage.modules is a dependency of only multi-variate Laurent polynomial ring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, see below


sage: F.<t> = GF(4) # optional - sage.rings.finite_rings
sage: LF.<a,b> = LaurentPolynomialRing(F) # optional - sage.rings.finite_rings
sage: rho = LF.hom([b,a], base_map=F.frobenius_endomorphism()) # optional - sage.rings.finite_rings
Copy link
Collaborator

Choose a reason for hiding this comment

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

No sage.modules here? I am getting confused...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This whole file is only shipped with sagemath-modules (#32432) because it cimports from sage.matrix.
(I split out this file from laurent_polynomial.pyx for this reason.)

Copy link
Collaborator

@kwankyu kwankyu Jun 2, 2023

Choose a reason for hiding this comment

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

Thus this whole business of adding (and not-adding) optional tags requires understanding of the hierarchy of distribution packages and which files are included in which distribution packages. This is very unlike with other doctest tags, which the author of the doctests can decide solely from his/her understanding of the code.

If the business is one time work (that is done and forgot), no matter. But every author that makes changes to doctests should be aware of the modularization structure of the sage codebase, not to break distribution packages.

I think we should later provide some tools or documentation to make the business easy and obvious.

Would Github actions testing distribution packages provide information to help authors decide on optional tags?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, there is a clear gap in the documentation - both in the code and in the formatted documentation.

In the code, the plan is to annotate each file with the name of the distribution that it is shipped by: # sage_setup: distribution = sagemath-combinat etc.; #35663 adds many of such annotations; this will enable consistency checks.

In the formatted documentation, file-level annotations # sage_setup: distribution and # sage.doctest: optional are not presented at all at the moment; in contrast to the line-level # optional annotations.
I don't have a clear plan yet how to improve it.

Yes, GH Actions will run the tests for the distributions after #35095, and this will flag any mistakes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

OK. Sounds nice.

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Jun 2, 2023

You use two idioms

lazy_import('sage.rings.padics.padic_generic_element', 'pAdicGenericElement')

and

try:
    from .laurent_series_ring_element import LaurentSeries
except ImportError:
    LaurentSeries = ()  

to modify module level imports of classes, for modularization. How are they different in terms of usage?

They have different performance characteristics, as explained in https://sagemath-tobias.netlify.app/developer/packaging_sage_library.html#module-level-runtime-dependencies

I think I tend to use the second idiom when the code that uses it seemed to be concerned about performance; but I am not sure that I have been entirely consistent with it.

The first idiom, on the other hand, looks more elegant; and by adding a feature=... argument to lazy_import, we can in the future provide users with installation information about the dependencies. (eager_import, proposed in #33820, could bring the second idiom on par with this.)

@github-actions
Copy link

github-actions bot commented Jun 2, 2023

Documentation preview for this PR (built with commit b9bf5bb) is ready! 🎉

@kwankyu
Copy link
Collaborator

kwankyu commented Jun 2, 2023

...eager_import, proposed in #33820, could bring the second idiom on par with this.

Good idea. Or perhaps you may add eager flag to lazy_import instead of introducing a new import statement.

Copy link
Collaborator

@kwankyu kwankyu left a comment

Choose a reason for hiding this comment

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

LGTM.

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Jun 2, 2023

Thanks for the review!

@vbraun vbraun merged commit 22999ff into sagemath:develop Jun 3, 2023
@mkoeppe mkoeppe added this to the sage-10.1 milestone Jun 3, 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