Skip to content

Introduce universal ring#2274

Open
SoongNoonien wants to merge 20 commits intoNemocas:masterfrom
SoongNoonien:univ_ring_test
Open

Introduce universal ring#2274
SoongNoonien wants to merge 20 commits intoNemocas:masterfrom
SoongNoonien:univ_ring_test

Conversation

@SoongNoonien
Copy link
Copy Markdown
Collaborator

This finally introduces the universal ring (#2172). Ideally, I'd like to get this into 0.48. I'm not sure if the hashing is what we want. There is no documentation on what a ring should implement to be a base ring of a universal ring and there are currently no tests which test this for other rings besides multivariate polynomial rings.

Let's see what the tests say, the doctest will fail as I haven't adjusted them yet.

Comment thread src/UnivPoly.jl Outdated
@SoongNoonien
Copy link
Copy Markdown
Collaborator Author

Ok, caching makes some problems. The caching now depends on the base ring which is created with cached = false by default. Is this what we want?

@SoongNoonien
Copy link
Copy Markdown
Collaborator Author

The remaining doctest failure is caused by the changed caching. We could adjust the universal_polynomial_ring constructor to only return the variables specified while constructing, even if there already are more variables. But then we should perhaps even change what number_of_variables does for a universal ring. Should it return Inf?

@lgoettgens
Copy link
Copy Markdown
Member

The remaining doctest failure is caused by the changed caching. We could adjust the universal_polynomial_ring constructor to only return the variables specified while constructing, even if there already are more variables. But then we should perhaps even change what number_of_variables does for a universal ring. Should it return Inf?

This is even worse than you describe. Consider the following:

julia> using AbstractAlgebra # aka fresh session

julia> universal_polynomial_ring(ZZ, [:x])
(Universal Polynomial Ring over Integers, AbstractAlgebra.Generic.UniversalRingElem{AbstractAlgebra.Generic.MPoly{BigInt}}[x])

julia> universal_polynomial_ring(ZZ, [:y])
(Universal Polynomial Ring over Integers, AbstractAlgebra.Generic.UniversalRingElem{AbstractAlgebra.Generic.MPoly{BigInt}}[x])

when I request a univ poly ring with variable y, I get one in variable x. This is a problem, which could be fixed by making the variables passed to the constructor be part of the cache key

Comment thread src/generic/GenericTypes.jl Outdated
@SoongNoonien
Copy link
Copy Markdown
Collaborator Author

This is a problem, which could be fixed by making the variables passed to the constructor be part of the cache key

Yes, this is true but ideally the caching shouldn't depend on the arbitrary variables passed on creation.

@lgoettgens
Copy link
Copy Markdown
Member

lgoettgens commented Jan 8, 2026

This is a problem, which could be fixed by making the variables passed to the constructor be part of the cache key

Yes, this is true but ideally the caching shouldn't depend on the arbitrary variables passed on creation.

This was requested in #1993 (comment) (apparently by @thofma, but I don't find the comment; just the one where @fingolfin suggests this)

Edit: found it: #1989 (comment)

@fingolfin
Copy link
Copy Markdown
Member

I specifically suggested to remove s (the list of variables) from the cache key when we talked about this earlier.

My reasoning for the removal was/is this: the primary reason we introduced universal polynomial rings in the first place was to accommodate users who are more used to systems like Mathematica and Maple, were you don't have to "define" variables or rings; if you need a new variable x, then you simply write x and be done. We can't quite reach that, but the universal polynomial ring is close to that.

For this kind of users, we also want caching. So that they don't want have to worry why there are multiple "different" x...

But if one gets different universal polynomials just depending on what the initial variables used where, that's defeating all of this.

Of course this is bad:

julia> using AbstractAlgebra # aka fresh session

julia> universal_polynomial_ring(ZZ, [:x])
(Universal Polynomial Ring over Integers, AbstractAlgebra.Generic.UniversalRingElem{AbstractAlgebra.Generic.MPoly{BigInt}}[x])

julia> universal_polynomial_ring(ZZ, [:y])
(Universal Polynomial Ring over Integers, AbstractAlgebra.Generic.UniversalRingElem{AbstractAlgebra.Generic.MPoly{BigInt}}[x])

But here the fix should be to adjust the constructor: change

function universal_polynomial_ring(R::Ring, varnames::Vector{Symbol}; cached::Bool=true, internal_ordering::Symbol=:lex)
   @req !is_trivial(R) "Zero rings are currently not supported as coefficient ring."
   T = elem_type(R)
   U = mpoly_type(R)

   S = Generic.UniversalPolyRing{T}(R, varnames, internal_ordering, cached)
   return (S, gens(S))
end

by replacing the return with

   return (S, gens(S, varnames))

@fingolfin
Copy link
Copy Markdown
Member

(That said: if this is controversial (it seems to be; I totally forgot about those past conversations Lars dug up), then we can of course also restore the use of s as cache key, and discuss its pros and cons in a future PR. I don't mean to sneak it in or rush it through.

Comment thread src/UnivPoly.jl
###############################################################################

function content(a::UniversalPolyRingElem)
function content(a::UniversalRingElem{<:MPolyRingElem})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this really necessary given the definition of UniversalPolyRingElem above?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No, it is not. But I thought that it would be better to not use the aliases where possible. Ideally they should just be there for increased backwards compatibility.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hmm, I think there is a lot of merit in keeping UniversalPolyRingElem around: it is easier to grasp and less technical than UniversalRingElem{<:MPolyRingElem}.

Plus, not changing it in this PR makes reviewing this PR that much easier, as I don't have to look over all those bits that don't really change anything ;-)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I forgot about this comment... @lgoettgens suggested to move the aliases to src/Deprecations.jl, which is what I did now. Is this fine by you @fingolfin or do you still think that we should keep them?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To keep this discussion here understandable on its own, let me repeat my argument. UniversalPolyRingElem{T} for a concrete T used to be a concrete type, but will not be concrete after this PR. Therefore, it should not be used as the eltype of a Vector etc. For places like here that just use it together with <: they would be fine to keep using. But I am not quite sure how to explain that in the docs and would thus just discourage use of the aliases altogether

Comment thread src/generic/GenericTypes.jl Outdated
Comment thread src/generic/UnivPoly.jl Outdated
Comment thread docs/src/univpolynomial.md Outdated
@SoongNoonien SoongNoonien force-pushed the univ_ring_test branch 4 times, most recently from 25dd4d6 to 13e8404 Compare January 13, 2026 11:12
@SoongNoonien
Copy link
Copy Markdown
Collaborator Author

I don't get this error message. Locally the respective line runs fine.

@SoongNoonien

This comment was marked as resolved.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 15, 2026

Codecov Report

❌ Patch coverage is 86.55172% with 78 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.13%. Comparing base (b873b3d) to head (89729b2).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/UniversalRing.jl 77.77% 50 Missing ⚠️
src/UnivPoly.jl 91.48% 28 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2274      +/-   ##
==========================================
+ Coverage   88.12%   88.13%   +0.01%     
==========================================
  Files         128      130       +2     
  Lines       32870    32871       +1     
==========================================
+ Hits        28966    28971       +5     
+ Misses       3904     3900       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/generic/UnivPoly.jl Outdated
Comment thread src/generic/UnivPoly.jl Outdated
Comment thread src/generic/UnivPoly.jl Outdated
Comment thread src/generic/UnivPoly.jl Outdated
Comment thread src/UnivPoly.jl Outdated
Comment thread src/generic/UnivPoly.jl Outdated
Comment thread src/generic/UnivPoly.jl Outdated
@SoongNoonien SoongNoonien force-pushed the univ_ring_test branch 3 times, most recently from d2069f5 to bb2ed4f Compare January 21, 2026 11:46
@lgoettgens
Copy link
Copy Markdown
Member

This PR has conflicts

@SoongNoonien
Copy link
Copy Markdown
Collaborator Author

Not anymore ;-)

Comment thread docs/src/universal_ring.md Outdated
Comment thread docs/src/universal_ring.md Outdated
Comment thread docs/src/universal_ring.md Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IMO this file could be merged into src/UniversalRing.jl to have the code less splattered around

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I tried that before but I had some problems which forced me somehow to export and import stuff back and forth between AbstractAlgebra.Generic and AbstractAlgebra.

Comment thread src/AbstractAlgebra.jl Outdated
Comment thread src/UniversalRing.jl Outdated
Comment thread src/UniversalRing.jl Outdated
Comment thread src/UniversalRing.jl
Comment on lines +43 to +45
zero(R::UniversalRing{T, U}) where {T, U} = UniversalRingElem{T, U}(zero(base_ring(R)), R)

one(R::UniversalRing{T, U}) where {T, U} = UniversalRingElem{T, U}(one(base_ring(R)), R)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
zero(R::UniversalRing{T, U}) where {T, U} = UniversalRingElem{T, U}(zero(base_ring(R)), R)
one(R::UniversalRing{T, U}) where {T, U} = UniversalRingElem{T, U}(one(base_ring(R)), R)
zero(R::UniversalRing{T, U}) where {T, U} = R(zero(base_ring(R)))
one(R::UniversalRing{T, U}) where {T, U} = R(one(base_ring(R)))

this should be equivalent but IMO better readable

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, this should be equivalent but this involves an additional coercion check. Shouldn't it be possible to drop the type parameters as well, if we were to do it like you proposed?

Comment thread src/UnivPoly.jl
Comment thread src/UnivPoly.jl
if length(a) != length(b)
return false
end
n1 = nvars(parent(data(a)))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why not upgrade here, as in isless below?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I don't know apparently this is supposed to be faster.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The fallback is implemented with an upgrade.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking breaks printing enhancement New feature or request release notes: use title For PRs: the title of this PR is suitable for direct use in the release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants