From 529c330f00dd60874296b753eef6b04cf7d10755 Mon Sep 17 00:00:00 2001 From: Tommy Hofmann Date: Sun, 11 Jun 2023 15:50:38 +0200 Subject: [PATCH] Add implicit canonical promotions for finite field arithmetic (#1491) --- src/flint/fq_default.jl | 65 +++++++++++++++----------- src/flint/fq_default_extended.jl | 48 ++++++++++++++++++- test/flint/fq_default_extended-test.jl | 34 ++++++++++++++ 3 files changed, 118 insertions(+), 29 deletions(-) diff --git a/src/flint/fq_default.jl b/src/flint/fq_default.jl index 171ca40223..44425917b5 100644 --- a/src/flint/fq_default.jl +++ b/src/flint/fq_default.jl @@ -387,27 +387,33 @@ end ############################################################################### function +(x::FqFieldElem, y::FqFieldElem) - check_parent(x, y) - z = parent(y)() - ccall((:fq_default_add, libflint), Nothing, - (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) - return z + if parent(x) === parent(y) + z = parent(y)() + ccall((:fq_default_add, libflint), Nothing, + (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) + return z + end + return +(_promote(x, y)...) end function -(x::FqFieldElem, y::FqFieldElem) - check_parent(x, y) - z = parent(y)() - ccall((:fq_default_sub, libflint), Nothing, - (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) - return z + if parent(x) === parent(y) + z = parent(y)() + ccall((:fq_default_sub, libflint), Nothing, + (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) + return z + end + return -(_promote(x, y)...) end function *(x::FqFieldElem, y::FqFieldElem) - check_parent(x, y) - z = parent(y)() - ccall((:fq_default_mul, libflint), Nothing, - (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) - return z + if parent(x) === parent(y) + z = parent(y)() + ccall((:fq_default_mul, libflint), Nothing, + (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) + return z + end + return *(_promote(x, y)...) end ############################################################################### @@ -515,22 +521,27 @@ end ############################################################################### function divexact(x::FqFieldElem, y::FqFieldElem; check::Bool=true) - check_parent(x, y) - iszero(y) && throw(DivideError()) - z = parent(y)() - ccall((:fq_default_div, libflint), Nothing, - (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) - return z + if parent(x) === parent(y) + iszero(y) && throw(DivideError()) + z = parent(y)() + ccall((:fq_default_div, libflint), Nothing, + (Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqFieldElem}, Ref{FqField}), z, x, y, y.parent) + return z + end + return divexact(_promote(x, y)...) end function divides(a::FqFieldElem, b::FqFieldElem) - if iszero(a) - return true, zero(parent(a)) - end - if iszero(b) - return false, zero(parent(a)) + if parent(a) === parent(b) + if iszero(a) + return true, zero(parent(a)) + end + if iszero(b) + return false, zero(parent(a)) + end + return true, divexact(a, b) end - return true, divexact(a, b) + return divides(_promote(a, b)...) end ############################################################################### diff --git a/src/flint/fq_default_extended.jl b/src/flint/fq_default_extended.jl index 85730f51f0..e46ba7e6c7 100644 --- a/src/flint/fq_default_extended.jl +++ b/src/flint/fq_default_extended.jl @@ -709,11 +709,11 @@ function (a::FqField)(b::FqFieldElem) end if k === base_field(a) - return (a.image_basefield)(b) + return (a.image_basefield)(b)::FqFieldElem end # To make it work in towers - return a(base_field(a)(b)) + return a(base_field(a)(b))::FqFieldElem end ################################################################################ @@ -826,3 +826,47 @@ function lift(R::FqPolyRing, a::FqFieldElem) return _lift_standard(R, a) end end + +################################################################################ +# +# Promotion +# +################################################################################ + +function _try_promote(K::FqField, a::FqFieldElem) + L = parent(a) + if degree(K) == 1 && K !== L + return false, a + end + + if K === L + return true, a + end + + fl, b = _try_promote(base_field(K), a) + if fl + return fl, K(a)::FqFieldElem + else + return false, a + end +end + +function _try_promote(a::FqFieldElem, b::FqFieldElem) + fl, c = _try_promote(parent(a), b) + if fl + return true, a, c + end + fl, c = _try_promote(parent(b), a) + if fl + return true, c, b + end + return false, a, b +end + +function _promote(a::FqFieldElem, b::FqFieldElem) + fl, aa, bb = _try_promote(a, b) + if fl + return aa, bb + end + error("Cannot promote to common finite field") +end diff --git a/test/flint/fq_default_extended-test.jl b/test/flint/fq_default_extended-test.jl index 00f55b6905..71dab12eee 100644 --- a/test/flint/fq_default_extended-test.jl +++ b/test/flint/fq_default_extended-test.jl @@ -254,3 +254,37 @@ end FF, = Nemo._FiniteField(x) @test iszero(FF(x)) end + +@testset "Implicit promotions" begin + F = Nemo._GF(2, 2) + FF = Nemo._GF(2, 3) + fl, = Nemo._try_promote(F, one(FF)) + @test !fl + fl, = Nemo._try_promote(FF, one(F)) + @test !fl + fl, = Nemo._try_promote(one(F), one(FF)) + @test !fl + + Fx, x = F["x"] + f = x^2 + gen(F)*x + 1 + FF, = Nemo._FiniteField(f) + for i in 1:10 + a, b = rand(F), rand(FF) + @test a * b == FF(a) * b + @test b * a == FF(a) * b + @test a + b == FF(a) + b + @test b + a == FF(a) + b + @test a - b == FF(a) - b + @test b - a == -(FF(a) - b) + @test divides(a, b) == divides(FF(a), b) + @test divides(b, a) == divides(b, FF(a)) + if !iszero(a) + @test divexact(b, a) == divexact(b, FF(a)) + end + @test divexact(b, one(F)) == divexact(b, one(FF)) + if !iszero(b) + @test divexact(a, b) == divexact(FF(a), b) + end + @test divexact(a, one(FF)) == divexact(FF(a), one(FF)) + end +end