Skip to content

Commit

Permalink
Make set_precision reduce the element (#1773)
Browse files Browse the repository at this point in the history
* Test edge cases

* Make `set_precision!` truncate the polynomial for generic types
  • Loading branch information
joschmitt authored Aug 25, 2024
1 parent b5a71a0 commit 6ee4435
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/RelSeries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ function set_length!(a::SeriesElem, len::Int)
return a
end

# TODO: set_precision! for the generic types RelSeries and AbsSeries
# truncates the underlying polynomial since #1773. In a breaking release,
# this should possibly also happen for the abstract types. Alternatively,
# this set_precision! should be renamed (and only be kept as a purely internal
# setter function).
function set_precision!(a::SeriesElem, prec::Int)
a.prec = prec
return a
Expand Down
20 changes: 20 additions & 0 deletions src/generic/AbsSeries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ function characteristic(a::AbsPowerSeriesRing{T}) where T <: RingElement
return characteristic(base_ring(a))
end

function set_precision!(a::AbsSeries, prec::Int)
prec < 0 && throw(DomainError(prec, "Precision must be non-negative"))
a = truncate!(a, prec)
a.prec = prec
return a
end

###############################################################################
#
# Binary operations
Expand Down Expand Up @@ -164,6 +171,19 @@ end
#
###############################################################################

function truncate!(a::AbsSeries{T}, n::Int) where T <: RingElement
n < 0 && throw(DomainError(n, "n must be >= 0"))
if precision(a) <= n
return a
end
a.length = min(n, length(a))
while length(a) != 0 && is_zero(coeff(a, length(a) - 1))
a.length -= 1
end
a.prec = n
return a
end

function zero!(c::AbsSeries{T}) where T <: RingElement
c.length = 0
c.prec = parent(c).prec_max
Expand Down
28 changes: 28 additions & 0 deletions src/generic/RelSeries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ function characteristic(a::RelPowerSeriesRing{T}) where T <: RingElement
return characteristic(base_ring(a))
end

function set_precision!(a::RelSeries, prec::Int)
prec < 0 && throw(DomainError(prec, "Precision must be non-negative"))
a = truncate!(a, prec)
a.prec = prec
if is_zero(a)
a.val = prec
end
return a
end

###############################################################################
#
# Binary operators
Expand Down Expand Up @@ -152,6 +162,24 @@ end
#
###############################################################################

function truncate!(a::RelSeries{T}, n::Int) where T <: RingElement
n < 0 && throw(DomainError(n, "n must be >= 0"))
if precision(a) <= n
return a
end
if n <= valuation(a)
a = zero!(a)
a.val = n
else
a.length = min(n - valuation(a), pol_length(a))
while is_zero(polcoeff(a, pol_length(a) - 1))
a.length -= 1
end
end
a.prec = n
return a
end

function zero!(a::RelSeries)
a.length = 0
a.prec = parent(a).prec_max
Expand Down
19 changes: 18 additions & 1 deletion test/generic/AbsSeries-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,10 @@ end
# Exact ring
R, x = power_series_ring(ZZ, 10, "x", model=:capped_absolute)

# Special case: length 1
f = R(2)
@test isequal(f^3, R(8))

for iter = 1:100
f = rand(R, 0:12, -10:10)
r2 = R(1)
Expand Down Expand Up @@ -1297,4 +1301,17 @@ end
@test is_unit(det(U))
@test is_unit(det(V))
end
end
end

@testset "Generic.AbsSeries.set_precision" begin
R, x = power_series_ring(QQ, 20, "x", model = :capped_absolute)
a = 1 + x + x^3 + O(x^5)
b = x^2 + O(x^3)

@test isequal(set_precision(a, 7), 1 + x + x^3 + O(x^7))
@test isequal(set_precision(a, 5), 1 + x + x^3 + O(x^5))
@test isequal(set_precision(a, 3), 1 + x + O(x^3))
@test isequal(set_precision(a, 0), O(x^0))
@test isequal(set_precision(b, 1), O(x))
@test is_zero(set_precision(b, 1))
end
19 changes: 18 additions & 1 deletion test/generic/RelSeries-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,10 @@ end
@testset "Generic.RelSeries.square_root" begin
# Exact ring
R, x = power_series_ring(ZZ, 10, "x")

# Special case: precision 0
@test is_zero(sqrt(O(x^0)))

for iter = 1:300
f = rand(R, 0:10, -10:10)
g = f^2
Expand Down Expand Up @@ -1333,4 +1337,17 @@ end
@test is_unit(det(U))
@test is_unit(det(V))
end
end
end

@testset "Generic.RelSeries.set_precision" begin
R, x = power_series_ring(QQ, 20, "x", model = :capped_relative)
a = 1 + x + x^3 + O(x^5)
b = x^2 + O(x^3)

@test isequal(set_precision(a, 7), 1 + x + x^3 + O(x^7))
@test isequal(set_precision(a, 5), 1 + x + x^3 + O(x^5))
@test isequal(set_precision(a, 3), 1 + x + O(x^3))
@test isequal(set_precision(a, 0), O(x^0))
@test isequal(set_precision(b, 1), O(x))
@test is_zero(set_precision(b, 1))
end

0 comments on commit 6ee4435

Please sign in to comment.