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

Is_unit and is_nilpotent (with tests) #1933

Draft
wants to merge 33 commits into
base: master
Choose a base branch
from

Conversation

JohnAAbbott
Copy link
Collaborator

Still a draft

src/LaurentMPoly.jl Outdated Show resolved Hide resolved
src/MPoly.jl Outdated Show resolved Hide resolved
src/MPoly.jl Outdated Show resolved Hide resolved
src/MPoly.jl Outdated Show resolved Hide resolved
src/MPoly.jl Outdated Show resolved Hide resolved
src/Poly.jl Outdated Show resolved Hide resolved
src/Poly.jl Show resolved Hide resolved
src/Rings.jl Outdated Show resolved Hide resolved
@thofma
Copy link
Member

thofma commented Dec 18, 2024

I don't think we can rely on any order when iterating over the coefficients. The only guarantee that we have is that coefficients and exponent[_vectors] have the same order. E.g., this is the implementation of constant_coefficient:

function constant_coefficient(p::MPolyRingElem{T}) where T <: RingElement
   if !iszero(p)
      for (c, v) in zip(coefficients(p), exponent_vectors(p))
         if iszero(v)
            return c
         end
      end
   end
   return zero(base_ring(p))
end

@JohnAAbbott
Copy link
Collaborator Author

I notice that there are tests of is_unit for Laurent series: for instance

./generic/LaurentSeries-test.jl:156:   @test is_unit(-1 + x + 2x^2)

Should I disable these tests? I have not yet checked which code would be called...
Perhaps it is simpler to leave things be?

Copy link

codecov bot commented Dec 19, 2024

Codecov Report

Attention: Patch coverage is 95.52239% with 3 lines in your changes missing coverage. Please review.

Project coverage is 87.89%. Comparing base (747df7d) to head (c10f880).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/NCRings.jl 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1933      +/-   ##
==========================================
- Coverage   88.21%   87.89%   -0.33%     
==========================================
  Files         119      119              
  Lines       30384    30397      +13     
==========================================
- Hits        26803    26717      -86     
- Misses       3581     3680      +99     

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

@fingolfin
Copy link
Member

I notice that there are tests of is_unit for Laurent series: for instance

./generic/LaurentSeries-test.jl:156:   @test is_unit(-1 + x + 2x^2)

Should I disable these tests? I have not yet checked which code would be called... Perhaps it is simpler to leave things be?

I don't understand. Why would you disable the tests?

Anyway, checking what code is called shouldn't be hard with @edit and @less, right?

is_constant(f) && return is_unit(constant_coefficient(f))
# Here deg(f) > 0; over an integral domain, non-constant polynomials are never units:
is_domain_type(elem_type(coefficient_ring(f))) && return false
for (c, expv) in zip(coefficients(f), exponent_vectors(f))
Copy link
Member

Choose a reason for hiding this comment

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

Can we add a comment explaining the math? E.g.

Suggested change
for (c, expv) in zip(coefficients(f), exponent_vectors(f))
# A polynomial over a commutative ring is a unit if and only if its
# constant term is a unit and all other coefficients are nilpotent.
# See URL/BOOKREF/SOMETHING for a proof.
for (c, expv) in zip(coefficients(f), exponent_vectors(f))

Obviously with a suitable source inserted.

src/MPoly.jl Outdated Show resolved Hide resolved
@JohnAAbbott
Copy link
Collaborator Author

I don't understand. Why would you disable the tests?

In general, we cannot always decide if a *-series is a unit: e.g. if no terms of the series are known, or if the only known terms all have nilpotent coefficients...

src/MPoly.jl Outdated
Comment on lines 452 to 453
function is_nilpotent(f::T) where {T<:MPolyRingElem}
is_domain_type(elem_type(coefficient_ring(f))) && return is_zero(f)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
function is_nilpotent(f::T) where {T<:MPolyRingElem}
is_domain_type(elem_type(coefficient_ring(f))) && return is_zero(f)
function is_nilpotent(f::MPolyRingElem{T}) where {T}
is_domain_type(T) && return is_zero(f)

would be IMHO more idiomatic (and simply much shorter to read).

The same could of course be used in is_unit above and elsewhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK, I'll try. I have found is_domain_type to be quite obstreperous, which is why I have used work-arounds. Maybe I should update...

Copy link
Member

Choose a reason for hiding this comment

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

Could you clarify what you found problematic about is_domain_type? What are you "working around"?

src/Rings.jl Outdated Show resolved Hide resolved
src/NCRings.jl Outdated
Comment on lines 159 to 160
function is_nilpotent(a::T) where { T <: NCRingElem }
is_domain_type(typeof(a)) && return is_zero(a)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
function is_nilpotent(a::T) where { T <: NCRingElem }
is_domain_type(typeof(a)) && return is_zero(a)
function is_nilpotent(a::T) where {T <: NCRingElem}
is_domain_type(T) && return is_zero(a)

Julia convention is to write {T <: NCRingElem} not { T <: NCRingElem }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can do what you prefer, but there are lots of other functions which use different spacing in the where clause e.g. no curly brackets, no spaces around <:,...

Copy link
Member

Choose a reason for hiding this comment

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

Sure. But I am not asking you to reformat the code, just to not introduce yet more variation. I just grepped the code base for AA and I found exactly one hit for where { (i.e., with a space after the opening curly brace), and that was in code that was (a) copied from another project and (b) trying to highlight a very specific pattern (i.e. it makes sense, locally, to format it that way).

Let's not introduce this new variation without need in new code, yes?

@fingolfin
Copy link
Member

As I expressed on several occasions, it'd be perfectly fine to ignore series completely for now, focus on getting the rest right, then after that is ready and merged, think more about dealing with series. So that we get the "easier" (not easy) bits done and usable, instead of getting bogged down in the more complicated (and less useful for us, currently) bits.

But since you are asking: we do implement is_zero and is_one for these rings, no? Then my view point would be that there is a clear definition for is_nilpotent and is_unit, too, no? If there is a positive integer k such that is_zero(x^k) holds, then x is nilpotent. And likewise, if there is a y such that is_one(x*y) then x is a unit.

Now whether this is useful is another question -- which is part of why I'd be OK with us raising an error if one of these functions is called on a series element.

@fingolfin
Copy link
Member

BTW, note that doctests in docs/src/polynomial.md are failing

@@ -40,6 +40,8 @@ one(::Rationals{T}) where T <: Integer = Rational{T}(1)

is_unit(a::Rational) = a != 0

is_nilpotent(a::Rational) = (a == 0)
Copy link
Member

Choose a reason for hiding this comment

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

Redundant?

@@ -42,6 +42,8 @@ one(::Integers{T}) where T <: Integer = T(1)

is_unit(a::Integer) = a == 1 || a == -1

is_nilpotent(a::Integer) = is_zero(a)
Copy link
Member

Choose a reason for hiding this comment

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

Redundant?

@test is_nilpotent(-x)
@test is_nilpotent(x+y)
@test is_nilpotent(x-y)
@test is_nilpotent(x*y)
Copy link
Member

Choose a reason for hiding this comment

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

Instead of adding these tests (which are very similar each time) into multiple places, it would be better to test them to the general ring interface test suite in test/Rings-conformance-tests.jl so that the tests get run for all our ring implementations (well, at least all that use the conformance tests).

Of course this may then reveal further issues, but so be it.

@fingolfin
Copy link
Member

I'd like to add that despite my many minor nitpicks, overall this PR seems to be shaping up and headed in the right direction. Thank you.

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.

3 participants