From 63fa792adae8a042d9fdf902d6f1519dad9e352a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Ahlb=C3=A4ck?= Date: Sun, 12 May 2024 21:08:43 +0200 Subject: [PATCH] Conform Nemo to new FLINT random struct * The GMP-state in a FLINT random context structure will no longer be expanded inside the struct, but rather a pointer to it. Hence, make Nemo compatible with this. * Do not use `flint_rand_alloc` and `flint_rand_free` for allocating the FLINT random context structure. This is in order to be able to use the same code for the new version of FLINT as well as the old version. * Use the new symbol names for the FLINT random functions if they are available. This is checked during the initialization of Nemo, where we check for the new symbol `flint_rand_init`. --- src/Nemo.jl | 35 ++++++++++++++++++++++++------- src/arb/Real.jl | 12 +++++------ src/arb/arb.jl | 12 +++++------ src/calcium/ca.jl | 12 +++++------ src/calcium/qqbar.jl | 6 +++--- src/flint/FlintTypes.jl | 46 ++++++++++++++++++++++++++++------------- src/flint/fmpq.jl | 4 ++-- src/flint/fmpz.jl | 12 +++++------ 8 files changed, 89 insertions(+), 50 deletions(-) diff --git a/src/Nemo.jl b/src/Nemo.jl index 8e1acf2a9..71686485f 100644 --- a/src/Nemo.jl +++ b/src/Nemo.jl @@ -214,6 +214,14 @@ function flint_abort() error("Problem in the Flint-Subsystem") end +_ptr = Libdl.dlopen(libflint) +if Libdl.dlsym(_ptr, :flint_rand_init; throw_error = false) !== nothing + const NEW_FLINT = true +else + const NEW_FLINT = false +end +Libdl.dlclose(_ptr) + ################################################################################ # # Debugging tools for allocation tracking @@ -525,14 +533,27 @@ end Random.seed!(a::rand_ctx, s::Nothing=nothing) = Random.seed!(a, rand(UInt128)) -flint_randseed!(a::rand_ctx, seed1::UInt, seed2::UInt) = - ccall((:flint_randseed, libflint), Cvoid, (Ptr{Cvoid}, UInt, UInt), a.ptr, seed1, seed2) +if NEW_FLINT + flint_randseed!(a::rand_ctx, seed1::UInt, seed2::UInt) = + ccall((:flint_rand_set_seed, libflint), Cvoid, (Ref{rand_ctx}, UInt, UInt), a, seed1, seed2) -function flint_gmp_randseed!(a::rand_ctx, seed::BigInt) - ccall((:_flint_rand_init_gmp, libflint), Cvoid, (Ptr{Cvoid},), a.ptr) - ccall((:__gmp_randseed, :libgmp), Cvoid, (Ptr{Cvoid}, Ref{BigInt}), - a.ptr, # gmp_state is the first field of a.ptr (cf. flint.h) - seed) + function flint_gmp_randseed!(a::rand_ctx, seed::BigInt) + if a.gmp_state == C_NULL + # gmp_state needs to be initialised + ccall((:_flint_rand_init_gmp_state, libflint), Cvoid, (Ref{rand_ctx},), a) + end + ccall((:__gmp_randseed, :libgmp), Cvoid, (Ptr{Cvoid}, Ref{BigInt}), a.gmp_state, seed) + end +else + flint_randseed!(a::rand_ctx, seed1::UInt, seed2::UInt) = + ccall((:flint_randseed, libflint), Cvoid, (Ref{rand_ctx}, UInt, UInt), a, seed1, seed2) + + function flint_gmp_randseed!(a::rand_ctx, seed::BigInt) + ccall((:_flint_rand_init_gmp, libflint), Cvoid, (Ref{rand_ctx},), a) + ccall((:__gmp_randseed, :libgmp), Cvoid, (Ref{rand_ctx}, Ref{BigInt}), + a, # gmp_state is the first field of flint_rand_s + seed) + end end ################################################################################ diff --git a/src/arb/Real.jl b/src/arb/Real.jl index a90110476..803d24cb7 100644 --- a/src/arb/Real.jl +++ b/src/arb/Real.jl @@ -2108,22 +2108,22 @@ function rand(r::RealField, prec::Int = precision(Balls); randtype::Symbol=:uran if randtype == :urandom ccall((:arb_urandom, libflint), Nothing, - (Ref{RealFieldElem}, Ptr{Cvoid}, Int), x, state.ptr, prec) + (Ref{RealFieldElem}, Ref{rand_ctx}, Int), x, state, prec) elseif randtype == :randtest ccall((:arb_randtest, libflint), Nothing, - (Ref{RealFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, prec, 30) + (Ref{RealFieldElem}, Ref{rand_ctx}, Int, Int), x, state, prec, 30) elseif randtype == :randtest_exact ccall((:arb_randtest_exact, libflint), Nothing, - (Ref{RealFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, prec, 30) + (Ref{RealFieldElem}, Ref{rand_ctx}, Int, Int), x, state, prec, 30) elseif randtype == :randtest_precise ccall((:arb_randtest_precise, libflint), Nothing, - (Ref{RealFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, prec, 30) + (Ref{RealFieldElem}, Ref{rand_ctx}, Int, Int), x, state, prec, 30) elseif randtype == :randtest_wide ccall((:arb_randtest_wide, libflint), Nothing, - (Ref{RealFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, prec, 30) + (Ref{RealFieldElem}, Ref{rand_ctx}, Int, Int), x, state, prec, 30) elseif randtype == :randtest_special ccall((:arb_randtest_special, libflint), Nothing, - (Ref{RealFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, prec, 30) + (Ref{RealFieldElem}, Ref{rand_ctx}, Int, Int), x, state, prec, 30) else error("Arb random generation `" * String(randtype) * "` is not defined") end diff --git a/src/arb/arb.jl b/src/arb/arb.jl index 3b49bc060..7e01150e0 100644 --- a/src/arb/arb.jl +++ b/src/arb/arb.jl @@ -2123,22 +2123,22 @@ function rand(r::ArbField; randtype::Symbol=:urandom) if randtype == :urandom ccall((:arb_urandom, libflint), Nothing, - (Ref{ArbFieldElem}, Ptr{Cvoid}, Int), x, state.ptr, r.prec) + (Ref{ArbFieldElem}, Ref{rand_ctx}, Int), x, state, r.prec) elseif randtype == :randtest ccall((:arb_randtest, libflint), Nothing, - (Ref{ArbFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, r.prec, 30) + (Ref{ArbFieldElem}, Ref{rand_ctx}, Int, Int), x, state, r.prec, 30) elseif randtype == :randtest_exact ccall((:arb_randtest_exact, libflint), Nothing, - (Ref{ArbFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, r.prec, 30) + (Ref{ArbFieldElem}, Ref{rand_ctx}, Int, Int), x, state, r.prec, 30) elseif randtype == :randtest_precise ccall((:arb_randtest_precise, libflint), Nothing, - (Ref{ArbFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, r.prec, 30) + (Ref{ArbFieldElem}, Ref{rand_ctx}, Int, Int), x, state, r.prec, 30) elseif randtype == :randtest_wide ccall((:arb_randtest_wide, libflint), Nothing, - (Ref{ArbFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, r.prec, 30) + (Ref{ArbFieldElem}, Ref{rand_ctx}, Int, Int), x, state, r.prec, 30) elseif randtype == :randtest_special ccall((:arb_randtest_special, libflint), Nothing, - (Ref{ArbFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, r.prec, 30) + (Ref{ArbFieldElem}, Ref{rand_ctx}, Int, Int), x, state, r.prec, 30) else error("Arb random generation `" * String(randtype) * "` is not defined") end diff --git a/src/calcium/ca.jl b/src/calcium/ca.jl index 1f7d4ea15..8b2b59b5e 100644 --- a/src/calcium/ca.jl +++ b/src/calcium/ca.jl @@ -139,16 +139,16 @@ function rand(C::CalciumField; depth::Int, bits::Int, if randtype == :null ccall((:ca_randtest, libflint), Nothing, - (Ref{CalciumFieldElem}, Ptr{Cvoid}, Int, Int, Ref{CalciumField}), - x, state.ptr, depth, bits, C) + (Ref{CalciumFieldElem}, Ref{rand_ctx}, Int, Int, Ref{CalciumField}), + x, state, depth, bits, C) elseif randtype == :rational ccall((:ca_randtest_rational, libflint), Nothing, - (Ref{CalciumFieldElem}, Ptr{Cvoid}, Int, Ref{CalciumField}), - x, state.ptr, bits, C) + (Ref{CalciumFieldElem}, Ref{rand_ctx}, Int, Ref{CalciumField}), + x, state, bits, C) elseif randtype == :special ccall((:ca_randtest_special, libflint), Nothing, - (Ref{CalciumFieldElem}, Ptr{Cvoid}, Int, Int, Ref{CalciumField}), - x, state.ptr, depth, bits, C) + (Ref{CalciumFieldElem}, Ref{rand_ctx}, Int, Int, Ref{CalciumField}), + x, state, depth, bits, C) else error("randtype not defined") end diff --git a/src/calcium/qqbar.jl b/src/calcium/qqbar.jl index 0125e46f1..9a258c506 100644 --- a/src/calcium/qqbar.jl +++ b/src/calcium/qqbar.jl @@ -341,14 +341,14 @@ function rand(R::QQBarField; degree::Int, bits::Int, if randtype == :null ccall((:qqbar_randtest, libflint), Nothing, - (Ref{QQBarFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, degree, bits) + (Ref{QQBarFieldElem}, Ref{rand_ctx}, Int, Int), x, state, degree, bits) elseif randtype == :real ccall((:qqbar_randtest_real, libflint), Nothing, - (Ref{QQBarFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, degree, bits) + (Ref{QQBarFieldElem}, Ref{rand_ctx}, Int, Int), x, state, degree, bits) elseif randtype == :nonreal degree < 2 && error("nonreal requires degree >= 2") ccall((:qqbar_randtest_nonreal, libflint), Nothing, - (Ref{QQBarFieldElem}, Ptr{Cvoid}, Int, Int), x, state.ptr, degree, bits) + (Ref{QQBarFieldElem}, Ref{rand_ctx}, Int, Int), x, state, degree, bits) else error("randtype not defined") end diff --git a/src/flint/FlintTypes.jl b/src/flint/FlintTypes.jl index 4c3c2f0d7..055793da4 100644 --- a/src/flint/FlintTypes.jl +++ b/src/flint/FlintTypes.jl @@ -6657,22 +6657,40 @@ end # ################################################################################ -mutable struct rand_ctx - ptr::Ptr{Cvoid} +if NEW_FLINT + mutable struct rand_ctx + gmp_state::Ptr{Cvoid} + randval::UInt + randval2::UInt + + function rand_ctx() + a = new() + ccall((:flint_rand_init, libflint), Cvoid, (Ref{rand_ctx},), a) + finalizer(_rand_ctx_clear_fn, a) + return a + end + end - function rand_ctx() - z = new() - z.ptr = ccall((:flint_rand_alloc, libflint), Ptr{Cvoid}, ( )) - ccall((:flint_randinit, libflint), Cvoid, (Ptr{Cvoid}, ), z.ptr) - finalizer(_rand_ctx_clear_fn, z) - return z - end -end + function _rand_ctx_clear_fn(a::rand_ctx) + ccall((:flint_rand_clear, libflint), Cvoid, (Ref{rand_ctx},), a) + nothing + end +else + mutable struct rand_ctx + data::NTuple{56, Int8} + + function rand_ctx() + a = new() + ccall((:flint_randinit, libflint), Cvoid, (Ref{rand_ctx},), a) + finalizer(_rand_ctx_clear_fn, a) + return a + end + end -function _rand_ctx_clear_fn(a::rand_ctx) - ccall((:flint_randclear, libflint), Cvoid, (Ptr{Cvoid}, ), a.ptr) - ccall((:flint_rand_free, libflint), Cvoid, (Ptr{Cvoid}, ), a.ptr) - nothing + function _rand_ctx_clear_fn(a::rand_ctx) + ccall((:flint_randclear, libflint), Cvoid, (Ref{rand_ctx},), a) + nothing + end end ################################################################################ diff --git a/src/flint/fmpq.jl b/src/flint/fmpq.jl index 84e65ab14..c5c8854e4 100644 --- a/src/flint/fmpq.jl +++ b/src/flint/fmpq.jl @@ -1155,8 +1155,8 @@ denominator can be smaller than $b$ bits. function rand_bits(::QQField, b::Int) b > 0 || throw(DomainError(b, "Bit count must be positive")) z = QQFieldElem() - ccall((:fmpq_randbits, libflint), Nothing, (Ref{QQFieldElem}, Ptr{Cvoid}, Int), - z, _flint_rand_states[Threads.threadid()].ptr, b) + ccall((:fmpq_randbits, libflint), Nothing, (Ref{QQFieldElem}, Ref{rand_ctx}, Int), + z, _flint_rand_states[Threads.threadid()], b) return z end diff --git a/src/flint/fmpz.jl b/src/flint/fmpz.jl index a2a0cb819..310a81fc3 100644 --- a/src/flint/fmpz.jl +++ b/src/flint/fmpz.jl @@ -1499,8 +1499,8 @@ function _ecm(a::ZZRingElem, B1::UInt, B2::UInt, ncrv::UInt, rnd = _flint_rand_states[Threads.threadid()]) f = ZZRingElem() r = ccall((:fmpz_factor_ecm, libflint), Int32, - (Ref{ZZRingElem}, UInt, UInt, UInt, Ptr{Cvoid}, Ref{ZZRingElem}), - f, ncrv, B1, B2, rnd.ptr, a) + (Ref{ZZRingElem}, UInt, UInt, UInt, Ref{rand_ctx}, Ref{ZZRingElem}), + f, ncrv, B1, B2, rnd, a) return r, f end @@ -2741,8 +2741,8 @@ Return a random signed integer whose absolute value has $b$ bits. function rand_bits(::ZZRing, b::Int) b >= 0 || throw(DomainError(b, "Bit count must be non-negative")) z = ZZRingElem() - ccall((:fmpz_randbits, libflint), Nothing,(Ref{ZZRingElem}, Ptr{Cvoid}, Int), - z, _flint_rand_states[Threads.threadid()].ptr, b) + ccall((:fmpz_randbits, libflint), Nothing,(Ref{ZZRingElem}, Ref{rand_ctx}, Int), + z, _flint_rand_states[Threads.threadid()], b) return z end @@ -2756,8 +2756,8 @@ function rand_bits_prime(::ZZRing, n::Int, proved::Bool = true) n < 2 && throw(DomainError(n, "No primes with that many bits")) z = ZZRingElem() ccall((:fmpz_randprime, libflint), Nothing, - (Ref{ZZRingElem}, Ptr{Cvoid}, Int, Cint), - z, _flint_rand_states[Threads.threadid()].ptr, n, Cint(proved)) + (Ref{ZZRingElem}, Ref{rand_ctx}, Int, Cint), + z, _flint_rand_states[Threads.threadid()], n, Cint(proved)) return z end