From c9aac857d0bdd13c5096af5b2103ada1aaf96c00 Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Sat, 15 Mar 2025 16:59:42 +0100 Subject: [PATCH 1/4] adding tests to reproduce the issue --- test/crt.jl | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 test/crt.jl diff --git a/test/crt.jl b/test/crt.jl new file mode 100644 index 00000000..dd2bceab --- /dev/null +++ b/test/crt.jl @@ -0,0 +1,30 @@ +@testset "CRT" begin + cases = [] + + push!(cases, + Dict( + :moduli => Vector{UInt64}([1099511627791, 3518437208889]), + :ai => Vector{UInt64}([8590035092, 8589936485]), + ) + ) + + for c in cases + ai = c[:ai] + moduli = c[:moduli] + M = prod(Vector{BigInt}(moduli)) + ci = Vector{BigInt}([0 for _ in moduli]) + n1, n2 = BigInt(0), BigInt(0) + Groebner.crt_precompute!(M, n1, n2, ci, moduli) + for i in 1:length(ci) + pii = div(M, moduli[i]) + @test ci[i] % pii == 0 + @test (ci[i] - 1) % moduli[i] == 0 + end + buf = BigInt(0) + Groebner.crt!(M, buf, n1, n2, ai, ci) + @test buf < M + for i in 1:length(ci) + @test (buf - ai[i]) % moduli[i] == 0 + end + end +end From c9bcd85cd730e3cf20672144fbf5bcf10eb63da1 Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Sat, 15 Mar 2025 18:51:59 +0100 Subject: [PATCH 2/4] inlcude in the test and hope for the best --- test/crt.jl | 9 +++++---- test/runtests.jl | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/crt.jl b/test/crt.jl index dd2bceab..ca5d932a 100644 --- a/test/crt.jl +++ b/test/crt.jl @@ -1,13 +1,14 @@ @testset "CRT" begin cases = [] - - push!(cases, + + push!( + cases, Dict( :moduli => Vector{UInt64}([1099511627791, 3518437208889]), - :ai => Vector{UInt64}([8590035092, 8589936485]), + :ai => Vector{UInt64}([8590035092, 8589936485]) ) ) - + for c in cases ai = c[:ai] moduli = c[:moduli] diff --git a/test/runtests.jl b/test/runtests.jl index 3c12528f..d05f2151 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -35,6 +35,7 @@ end @time @testset "All tests" verbose = true begin @time include("arithmetic.jl") + @time include("crt.jl") # Different implementations of a monomial @time include("monoms/exponentvector.jl") From 239d22f87037eff902b2d03ff262dafe13ae5b2b Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Sun, 16 Mar 2025 00:31:38 +0100 Subject: [PATCH 3/4] avoiding overflow + more tests --- src/reconstruction/crt.jl | 48 +++++++++++++++++++++++++++++++++++---- test/crt.jl | 12 ++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/reconstruction/crt.jl b/src/reconstruction/crt.jl index 05f6ffb7..fc7c8c2d 100644 --- a/src/reconstruction/crt.jl +++ b/src/reconstruction/crt.jl @@ -3,6 +3,44 @@ ### # CRT +# Auxiliary functions allowing to avoid overflow +# on Windows for numbers between 32 and 64 bits +function my_set_ui!(a::BigInt, b::UInt64) + @static if Culong == UInt64 + Base.GMP.MPZ.set_ui!(a, b) + else + if b < 2^32 + Base.GMP.MPZ.set_ui!(a, b) + else + Base.GMP.MPZ.set!(a, BigInt(b)) + end + end +end + +function my_mul_ui!(a::BigInt, b::BigInt, c::UInt64) + @static if Culong == UInt64 + Base.GMP.MPZ.mul_ui!(a, b, c) + else + if c < 2^32 + Base.GMP.MPZ.mul_ui!(a, b, c) + else + Base.GMP.MPZ.mul!(a, b, BigInt(c)) + end + end +end + +function my_mul_ui!(a::BigInt, b::UInt64) + @static if Culong == UInt64 + Base.GMP.MPZ.mul_ui!(a, b) + else + if b < 2^32 + Base.GMP.MPZ.mul_ui!(a, b) + else + Base.GMP.MPZ.mul!(a, BigInt(b)) + end + end +end + """ crt! @@ -23,9 +61,9 @@ Then, `x` is obtained as `x = ∑ ci[i] ai[i] mod M`. function crt!(M::BigInt, buf::BigInt, n1::BigInt, n2::BigInt, ai::Vector{UInt}, ci::Vector{BigInt}) @invariant length(ai) == length(ci) - Base.GMP.MPZ.set_ui!(n1, UInt(0)) + my_set_ui!(n1, UInt(0)) for i in 1:length(ai) - Base.GMP.MPZ.mul_ui!(n2, ci[i], ai[i]) + my_mul_ui!(n2, ci[i], ai[i]) Base.GMP.MPZ.add!(n1, n2) end @@ -52,13 +90,13 @@ function crt_precompute!( @invariant length(ci) == length(moduli) n3, n4 = BigInt(), BigInt() - @inbounds Base.GMP.MPZ.set_ui!(M, moduli[1]) + @inbounds my_set_ui!(M, moduli[1]) @inbounds for i in 2:length(moduli) - Base.GMP.MPZ.mul_ui!(M, moduli[i]) + my_mul_ui!(M, moduli[i]) end @inbounds for i in 1:length(moduli) - Base.GMP.MPZ.set_ui!(n2, moduli[i]) + my_set_ui!(n2, moduli[i]) Base.GMP.MPZ.tdiv_q!(ci[i], M, n2) Base.GMP.MPZ.gcdext!(n2, n3, n4, ci[i], n2) Base.GMP.MPZ.mul!(ci[i], n3) diff --git a/test/crt.jl b/test/crt.jl index ca5d932a..45f0cd1e 100644 --- a/test/crt.jl +++ b/test/crt.jl @@ -6,6 +6,18 @@ Dict( :moduli => Vector{UInt64}([1099511627791, 3518437208889]), :ai => Vector{UInt64}([8590035092, 8589936485]) + ), + Dict( + :moduli => Vector{UInt64}([1099511627791, 17, 3518437208889]), + :ai => Vector{UInt64}([8590035092, 3, 8589936485]) + ), + Dict( + :moduli => Vector{UInt64}([1099511627791, 2^30 + 3, 3518437208889]), + :ai => Vector{UInt64}([8590035092, 42, 0]) + ), + Dict( + :moduli => Vector{UInt64}([1099511627791, 2^30 + 3, 3518437208889]), + :ai => Vector{UInt64}([0, 0, 0]) ) ) From 393eac37e279be3c9bf7278e84884543b49d01db Mon Sep 17 00:00:00 2001 From: pogudingleb Date: Sun, 16 Mar 2025 20:33:00 +0100 Subject: [PATCH 4/4] checking lower bound in a test --- test/crt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crt.jl b/test/crt.jl index 45f0cd1e..8c2cec39 100644 --- a/test/crt.jl +++ b/test/crt.jl @@ -35,7 +35,7 @@ end buf = BigInt(0) Groebner.crt!(M, buf, n1, n2, ai, ci) - @test buf < M + @test 0 <= buf < M for i in 1:length(ci) @test (buf - ai[i]) % moduli[i] == 0 end