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

Added new func is_unimodular for square integer matrices #1991

Merged
merged 8 commits into from
Jan 16, 2025

Conversation

JohnAAbbott
Copy link
Collaborator

Added new func is_unimodular for square integer matrices

Copy link

codecov bot commented Jan 14, 2025

Codecov Report

Attention: Patch coverage is 96.59091% with 6 lines in your changes missing coverage. Please review.

Project coverage is 88.14%. Comparing base (6e20099) to head (f6c2d67).
Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
src/matrix.jl 96.57% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1991      +/-   ##
==========================================
+ Coverage   88.08%   88.14%   +0.05%     
==========================================
  Files          98       98              
  Lines       36031    36207     +176     
==========================================
+ Hits        31737    31913     +176     
  Misses       4294     4294              

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

@JohnAAbbott
Copy link
Collaborator Author

I am not planning to make further changes to increase test coverage (currently 96%).

@fieker fieker merged commit f143dcb into Nemocas:master Jan 16, 2025
24 checks passed
@JohnAAbbott JohnAAbbott deleted the JAA/is_unimodular branch January 16, 2025 10:34
@thofma
Copy link
Member

thofma commented Jan 16, 2025

There are some issues, for example, the use of floating point numbers here:

if det_mod_p > p/2

and plenty of unnecessary Nemo. and ;.

@JohnAAbbott
Copy link
Collaborator Author

OK, mostly minor syntactic quibbles, right? The code should be mathematically sound.
I didn't know that floats are verboten. Semicolons are needed to separate commands on a single line, and when commands go strongly hand-in-hand it makes sense to put them together on one line (IMHO).

@thofma
Copy link
Member

thofma commented Jan 16, 2025

The 2^56 looks a bit wrong. Should probably be something like 2^(7 * sizeof(Int))?

@JohnAAbbott
Copy link
Collaborator Author

What is our stance on supporting platforms which are not 64-bit? I'd guess that 32-bit is probably "impossible" and/or pointless; or do we really support Int == Int32? Maybe we support 128-bit?
Perhaps I'd prefer something like (sizeof(Int) == 8) ? 2^56 : error("unsupported platform").
On my computer here computations with 21-22 bit primes were quick, but there was already a significant penalty for 23-bit primes: it was then better to jump to much larger primes (57-bit worked well on my computer). Ideally there would be an automatic "tuning" phase where these values are computed at start-up in Oscar....

@fieker
Copy link
Contributor

fieker commented Jan 16, 2025 via email

@thofma
Copy link
Member

thofma commented Jan 16, 2025

  for i=1:nrows(A)
    A_p = Nemo.mat_entry_ptr(A, i, i)
    sub!(A_p, A_p, m)
  end

this needs a GC.@preserve and similar for the other function.

Why is this a problem? This is to get a symmetric lift to char 0...

I was thinking of things like this

julia> (2^61 + 1) > (2^62 + 2)/2
true

julia> (2^61 + 1) > (2^62 + 2)//2
false

Or I might have mistaken the intended use of floating point stuff here.

@fieker
Copy link
Contributor

fieker commented Jan 16, 2025 via email

@fieker
Copy link
Contributor

fieker commented Jan 16, 2025 via email

Copy link
Member

@fingolfin fingolfin left a comment

Choose a reason for hiding this comment

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

Didn't manage to comment on this in time, sorry. It would be good if some of these were still addressed, though

Comment on lines +445 to +454
function Nemo.mul!(A::ZZMatrix, m::ZZRingElem)
for i=1:nrows(A)
A_p = Nemo.mat_entry_ptr(A, i, 1)
for j=1:ncols(A)
mul!(A_p, A_p, m)
A_p += sizeof(Int)
end
end
return A
end
Copy link
Member

Choose a reason for hiding this comment

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

But we already define such a method in src/flint/fmpz_mat.jl:

function mul!(z::ZZMatrixOrPtr, a::ZZMatrixOrPtr, b::ZZRingElemOrPtr)
  @ccall libflint.fmpz_mat_scalar_mul_fmpz(z::Ref{ZZMatrix}, a::Ref{ZZMatrix}, b::Ref{ZZRingElem})::Nothing
  return z
end

(and then generic code in AA also makes mul!(::ZZMatrix, ::ZZRingElem) available.

# add_verbosity_scope(:UnimodVerif) -- see func __init__ in src/Nemo.jl

#######################################################
# Low-level auxiliary functions -- should be elsewhere?
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I would say most of the coded added here should actually be in src/flint/fmpz_mat.jl

return r
end

function map_entries!(a::fpMatrix, k::Nemo.fpField, A::ZZMatrix)
Copy link
Member

Choose a reason for hiding this comment

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

The argument order clashes with the general map_entries! signature as defined in AA which is map_entries!(f, dst::MatrixElem{T}, src::MatrixElem{U})

Comment on lines +476 to +478
if !is_square(A)
throw(ArgumentError("Matrix must be square"))
end
Copy link
Member

Choose a reason for hiding this comment

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

While this is fine, I'd recommend to use the @req macro liberally for such tests:

Suggested change
if !is_square(A)
throw(ArgumentError("Matrix must be square"))
end
@req is_square(A) "Matrix must be square"

ZZmodP = Nemo.Native.GF(p; cached = false, check = false)
map_entries!(A_mod_p, ZZmodP, A)
@vtime :UnimodVerif 2 det_mod_p = Int(_det(A_mod_p))
if det_mod_p > p/2
Copy link
Member

Choose a reason for hiding this comment

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

While the cost for converting ints to float etc. here, it could indeed still be avoided here, e.g. via use of >>

Suggested change
if det_mod_p > p/2
if det_mod_p > p>>1

return false # obviously not unimodular
end
det_mod_m = det_mod_p
mul!(M, M, p)
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
mul!(M, M, p)
M = mul!(M, p)

Comment on lines +518 to +519
# THIS FUNCTION NOT OFFICIALLY DOCUMENTED -- not intended for public use.
function is_unimodular_given_det_mod_m(A::ZZMatrix, det_mod_m::Int, M::ZZRingElem; algorithm=:auto)
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 a code comment which nobody will see, I suggest we start using a prefix like _ to indicate internal functions:

Suggested change
# THIS FUNCTION NOT OFFICIALLY DOCUMENTED -- not intended for public use.
function is_unimodular_given_det_mod_m(A::ZZMatrix, det_mod_m::Int, M::ZZRingElem; algorithm=:auto)
function _is_unimodular_given_det_mod_m(A::ZZMatrix, det_mod_m::Int, M::ZZRingElem; algorithm=:auto)

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.

4 participants