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

Optimize map_coefficients, change_base_ring for some inputs #1994

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions src/HeckeMoreStuff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -182,21 +182,6 @@ function Base.hash(f::zzModMPolyRingElem, h::UInt)
return UInt(1) # TODO: enhance or throw error
end

function AbstractAlgebra.map_coefficients(F::fpField, f::QQMPolyRingElem; parent=polynomial_ring(F, nvars(parent(f)), cached=false)[1])
Copy link
Member Author

Choose a reason for hiding this comment

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

the parent computation here was wrong as it ignored the internal ordering

dF = denominator(f)
d = F(dF)
if iszero(d)
error("Denominator divisible by p!")
end
m = inv(d)
ctx = MPolyBuildCtx(parent)
for x in zip(coefficients(f), exponent_vectors(f))
el = numerator(x[1] * dF)
push_term!(ctx, F(el) * m, x[2])
end
return finish(ctx)
end

function tdivpow2!(B::ZZMatrix, t::Int)
@ccall libflint.fmpz_mat_scalar_tdiv_q_2exp(B::Ref{ZZMatrix}, B::Ref{ZZMatrix}, t::Cint)::Nothing
end
Expand Down
63 changes: 63 additions & 0 deletions src/flint/fmpq_mpoly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,11 @@
#
###############################################################################

_content_ptr(c::QQMPolyRingElem) = Ptr{QQFieldElem}(pointer_from_objref(c))
_content_ptr(c::Ptr{QQMPolyRingElem}) = Ptr{QQFieldElem}(c)
_content_ptr(c::Ref{QQMPolyRingElem}) = _content_ptr(c[])

Check warning on line 662 in src/flint/fmpq_mpoly.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpq_mpoly.jl#L661-L662

Added lines #L661 - L662 were not covered by tests
_zpoly_ptr(c::QQMPolyRingElemOrPtr) = Ptr{ZZMPolyRingElem}(_content_ptr(c) + sizeof(QQFieldElem))

function zero!(a::QQMPolyRingElem)
@ccall libflint.fmpq_mpoly_zero(a::Ref{QQMPolyRingElem}, a.parent::Ref{QQMPolyRing})::Nothing
return a
Expand Down Expand Up @@ -760,6 +765,20 @@
mul!(a::QQMPolyRingElem, b::QQMPolyRingElem, c::RationalUnion) = mul!(a, b, flintify(c))
mul!(a::QQMPolyRingElem, b::RationalUnion, c::QQMPolyRingElem) = mul!(a, c, b)

# special: multiply a QQMPolyRingElem by an integer and store the result as a ZZMPolyRingElem.
# obviously this only works if the integers is a multiple of the denominator of the polynomial
function mul!(a::ZZMPolyRingElem, b::QQMPolyRingElem, c::IntegerUnion)
x = QQFieldElem()
GC.@preserve a b x begin
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
GC.@preserve a b x begin
GC.@preserve b x begin

x = mul!(x, _content_ptr(b), c)
bp = _zpoly_ptr(b)
lgoettgens marked this conversation as resolved.
Show resolved Hide resolved
xp = _num_ptr(x)
@ccall libflint.fmpz_mpoly_scalar_mul_fmpz(a::Ref{ZZMPolyRingElem}, bp::Ref{ZZMPolyRingElem}, xp::Ref{ZZRingElem}, parent(a)::Ref{ZZMPolyRing})::Nothing
end
return a
end


divexact!(a::QQMPolyRingElem, b::QQMPolyRingElem, c::RationalUnion) = divexact!(a, b, flintify(c))

# Set the n-th coefficient of a to c. If zero coefficients are inserted, they
Expand Down Expand Up @@ -1059,3 +1078,47 @@

return R(newaa, newbb)
end

###############################################################################
#
# Changing base ring, mapping coefficients
#
###############################################################################

function map_coefficients(R::ZZRing, f::QQMPolyRingElem;
cached::Bool = true,
parent::ZZMPolyRing = AbstractAlgebra._change_mpoly_ring(R, parent(f), cached))
@req isinteger(_content_ptr(f)) "input polynomial must have integral coefficients"
@req ngens(parent) == ngens(Nemo.parent(f)) "parents must have matching numbers of generators"
@req internal_ordering(parent) == internal_ordering(Nemo.parent(f)) "parents must have matching internal ordering"
Copy link
Member Author

Choose a reason for hiding this comment

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

Is this too strict? Maybe instead of erroring out when the orderings don't match we should fall back to the generic code ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

How do other methods of map_coefficients handle this? The one below works for different internal orderings, so IMO this one should do so as well, e.g. by delegating to some more generic approach

Copy link
Member Author

Choose a reason for hiding this comment

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

Ahh apparently I can use sort_terms! to solve this

Copy link
Member Author

Choose a reason for hiding this comment

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

(A test case should also be added to verify this works as desired)

return mul!(zero(parent), f, 1)
end

function map_coefficients(F::fpField, f::QQMPolyRingElem;

Check warning on line 1097 in src/flint/fmpq_mpoly.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpq_mpoly.jl#L1097

Added line #L1097 was not covered by tests
Copy link
Member Author

Choose a reason for hiding this comment

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

Apparently this function is untested so a test should be added (TODO)

cached::Bool = true,
parent::MPolyRing = AbstractAlgebra._change_mpoly_ring(F, parent(f), cached))
dF = denominator(f)
d = F(dF)
if iszero(d)
error("Denominator divisible by p!")

Check warning on line 1103 in src/flint/fmpq_mpoly.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpq_mpoly.jl#L1100-L1103

Added lines #L1100 - L1103 were not covered by tests
end
m = inv(d)
ctx = MPolyBuildCtx(parent)
for x in zip(coefficients(f), exponent_vectors(f))
el = numerator(x[1] * dF)
Copy link
Member Author

Choose a reason for hiding this comment

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

Could optimize this further by using _zpoly_ptr (to avoid converting the internal fmpz coefficients into fmpq, and then back via a multiplication)

push_term!(ctx, F(el) * m, x[2])
end
return finish(ctx)

Check warning on line 1111 in src/flint/fmpq_mpoly.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpq_mpoly.jl#L1105-L1111

Added lines #L1105 - L1111 were not covered by tests
end

function change_base_ring(R::ZZRing, f::QQMPolyRingElem;
cached::Bool = true,
parent::ZZMPolyRing = AbstractAlgebra._change_mpoly_ring(R, parent(f), cached))
return map_coefficients(R, f; cached, parent)
end

function change_base_ring(F::fpField, f::QQMPolyRingElem;

Check warning on line 1120 in src/flint/fmpq_mpoly.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpq_mpoly.jl#L1120

Added line #L1120 was not covered by tests
cached::Bool = true,
parent::fpMPolyRing = AbstractAlgebra._change_mpoly_ring(F, parent(f), cached))
return map_coefficients(R, f; cached, parent)

Check warning on line 1123 in src/flint/fmpq_mpoly.jl

View check run for this annotation

Codecov / codecov/patch

src/flint/fmpq_mpoly.jl#L1123

Added line #L1123 was not covered by tests
end
17 changes: 17 additions & 0 deletions test/flint/fmpq_mpoly-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -813,3 +813,20 @@ end
@test abc - a - b == c
@test abc - ab == c
end

@testset "QQMPolyRingElem.convert_to_ZZMPolyRingElem" begin
Qxy, (x,y) = QQ[:x,:y]
f = 11*(x^2/2 + ZZ(3)^50*x*y^5/7 + y^6/12)

Zxy, (x,y) = ZZ[:u,:v]
g = 462*x^2 + 94762534375324541717672868*x*y^5 + 77*y^6

@test g == @inferred mul!(zero(Zxy), f, 84)
@test g == change_base_ring(ZZ, f*84; parent = Zxy)
@test g == map_coefficients(ZZ, f*84; parent = Zxy)

# test error handling
@test_throws ArgumentError change_base_ring(ZZ, f; parent = Zxy)
@test_throws ArgumentError map_coefficients(ZZ, f; parent = Zxy)

end
Loading