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

Make factor work for Int128, UInt128, BigInt #1951

Merged
merged 3 commits into from
Nov 28, 2024

Conversation

JohnAAbbott
Copy link
Contributor

No description provided.

Copy link

codecov bot commented Nov 28, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 87.92%. Comparing base (fd3ff47) to head (8f143f9).
Report is 2 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1951   +/-   ##
=======================================
  Coverage   87.92%   87.92%           
=======================================
  Files          99       99           
  Lines       36404    36416   +12     
=======================================
+ Hits        32007    32018   +11     
- Misses       4397     4398    +1     

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

# trivial case: input is 1
F1 = factor(1)
F1_ZZ = factor(ZZ(1))
@test length(F1.fac) == 0
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
@test length(F1.fac) == 0
@test length(F1) == 0

this should work

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, thanks for the suggested clean up. I have just checked in the relevant changes.

Copy link
Member

Choose a reason for hiding this comment

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

@JohnAAbbott Maybe you checked them in but did not push them? They don't appear to be in the merged code. Perhaps send a follow-up PR to clean that up?

@thofma thofma merged commit c77cb33 into Nemocas:master Nov 28, 2024
24 checks passed
for i in 1:F.num
z = F.p[i]
res[z] = F.exp[i]
end
return Fac(u, res)
end

# This is supposed to be called only for T in [Int128, UInt128, BigInt]
Copy link
Member

Choose a reason for hiding this comment

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

I don't really understand this comment. The code clearly can also be called for e.g. T equal to Int16. So who is supposed to "only" call it for the listed types? What happens if I call it with another Julia Integer type? Is there a problem (then we should address it)? Or is actually all fine (then remove this comment?)

function factor(a::T) where T <: Integer
iszero(a) && throw(ArgumentError("Argument must be non-zero"))
u = sign(a)
F = factor(ZZ(abs(a)))
Copy link
Member

Choose a reason for hiding this comment

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

Another thing you could try in a follow-up PR: if T is an Integer type that is "smaller" than Int or UInt, this might be more efficient:

Suggested change
F = factor(ZZ(abs(a)))
F = factor(flintify(abs(a)))

Check out the docstring for Nemo.flintify to get an explanation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the hint. Note that flintify seems always to give a ZZRingElem when the supplied value is Unsigned; is this intentional?

@thofma
Copy link
Member

thofma commented Nov 29, 2024

I think some .fac calls were missed 8f143f9.

@JohnAAbbott can you open a new PR to fix this? The test should test the interface and not internals.

throw(DomainError("Cannot factorize a boolean"));
end

# This function handles machine integer types (up to 64 bits)
function factor(a::T) where T <: Union{Int, UInt}
iszero(a) && throw(ArgumentError("Argument must be non-zero"))
u = sign(a)
a = u < 0 ? -a : a
Copy link
Member

Choose a reason for hiding this comment

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

This code is actually incorrect if a == typemin(Int), as then -a == a and we get an error casting that negative value to UInt.

But instead of fixing this locally, I suggest a slightly bigger change which then also allows avoiding creating Dictionaries twice:

Change this function to look like roughly this (might contain syntax errors):

function factor(::Type{T}, a::UInt) where T <: Integer
  iszero(a) && throw(ArgumentError("Argument must be non-zero"))
  F = n_factor()
  # ... now continue as before
end

factor(a::UInt) = factor(UInt, a)

I.e. the caller can specify T.

Then continue:

# another base cased, needed because `flintify` may produce `Int`
function factor(::Type{T}, a::Int) where T <: Integer
  u = reinterpret(UInt, a < 0 ? -a : a)
  return factor(T, u)
end

function factor(a::T) where T <: Integer
  return factor(T, flintify(a))
end

function factor(::Type{T}, N::ZZRingElem) where T <: Integer
  F = factor(N)
  res = Dict{T, Int}()  # factor-multiplicity pairs
  for (fac,exp) in F.fac
    res[T(fac)] = exp
  end
  return Fac(u, res)
end

Of course the final function is also not optimal, better would be to modify function factor(N::ZZRingElem) to take T as argument and use it, but that could be done later (in any case this is no worse than what your code right now).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I decided not to alter factor(::ZZRingElem) whose implementation is "special" (and possibly fragile?).

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