Skip to content

Commit

Permalink
Add implicit canonical promotions for finite field arithmetic (#1491)
Browse files Browse the repository at this point in the history
  • Loading branch information
thofma authored Jun 11, 2023
1 parent 95c1424 commit 529c330
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 29 deletions.
65 changes: 38 additions & 27 deletions src/flint/fq_default.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

###############################################################################
Expand Down Expand Up @@ -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

###############################################################################
Expand Down
48 changes: 46 additions & 2 deletions src/flint/fq_default_extended.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

################################################################################
Expand Down Expand Up @@ -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
34 changes: 34 additions & 0 deletions test/flint/fq_default_extended-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 529c330

Please sign in to comment.