Skip to content

Commit c3e9a02

Browse files
chrhanskblegat
andauthored
Add antidifferentiation (#158)
* Add antidifferentiation for monomials * Add antidifferentiation for polynomials * Add support for rational coefficients in antidifferentiation * Update src/anti_diff.jl Co-authored-by: Benoît Legat <[email protected]> * Remove superfluous print * Use coefficient_type in polynomial antidifferentiaton tests * Make monomial antidifferentiation coefficient types rationals --------- Co-authored-by: Benoît Legat <[email protected]>
1 parent 005621b commit c3e9a02

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed

src/DynamicPolynomials.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ include("promote.jl")
8484
include("operators.jl")
8585
include("comp.jl")
8686

87+
include("anti_diff.jl")
8788
include("diff.jl")
8889
include("subs.jl")
8990

src/anti_diff.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
function _div_by_power(x::T, y::Int) where {T}
2+
x / y
3+
end
4+
5+
function _div_by_power(x::T, y::Int)::Rational{T} where {T<:Integer}
6+
x // y
7+
end
8+
9+
function MP.antidifferentiate(m::Monomial{V,M}, x::Variable{V,M}) where {V,M}
10+
z = copy(m.z)
11+
i = findfirst(isequal(x), MP.variables(m))
12+
if (i === nothing || i == 0) || m.z[i] == 0
13+
Monomial(MP.variables(m), z) * x
14+
else
15+
z[i] += 1
16+
(1 // (m.z[i] + 1)) * Monomial(MP.variables(m), z)
17+
end
18+
end
19+
20+
function MP.antidifferentiate(p::Polynomial{V,M,T}, x::Variable{V,M}) where {V,M,T}
21+
i = something(findfirst(isequal(x), MP.variables(p)), 0)
22+
S = typeof(_div_by_power(zero(T), Int(1)))
23+
if iszero(i)
24+
x * p
25+
else
26+
Z = copy.(p.x.Z)
27+
a = Vector{S}(undef, length(p.a))
28+
for j in 1:length(Z)
29+
a[j] = _div_by_power(p.a[j], (Z[j][i] + 1))
30+
Z[j][i] += 1
31+
end
32+
Polynomial(a, MonomialVector(MP.variables(p), Z))
33+
end
34+
end

test/mono.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,28 @@ import MultivariatePolynomials as MP
141141
@test m.z == [2, 1, 1, 0, 0]
142142
end
143143

144+
@testset "Antidifferentiation" begin
145+
@ncpolyvar x y z
146+
147+
m = x
148+
mi = DynamicPolynomials.MP.antidifferentiate(m, y)
149+
@test mi == x * y
150+
151+
# Antidifferentiation is product => Integral coefficients
152+
@test MP.coefficient_type(mi) == Int
153+
154+
# General antidifferentiation => Rational coefficients
155+
m = x^3
156+
mi = DynamicPolynomials.MP.antidifferentiate(m, x)
157+
@test mi == (x^4 / 4)
158+
@test MP.coefficient_type(mi) == Rational{Int}
159+
160+
m = Monomial([x, y, z], [1, 2, 3])
161+
mi = DynamicPolynomials.MP.antidifferentiate(m, z)
162+
@test mi == (x*y^2*z^4) / 4
163+
@test MP.coefficient_type(mi) == Rational{Int}
164+
end
165+
144166
@testset "Evaluation" begin
145167
@polyvar x y
146168
@test (x^2 * y)(3, 2) == 18

test/poly.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,34 @@
8181
@inferred polynomial(2.0u, Int)
8282
end
8383

84+
@testset "Antiderivative" begin
85+
@polyvar x y
86+
87+
p = (x^2 + 4 * y^3)
88+
@test MP.coefficient_type(p) == Int
89+
90+
pi = DynamicPolynomials.antidifferentiate(p, y)
91+
@test pi == (x^2 * y + y^4)
92+
93+
pi = DynamicPolynomials.antidifferentiate(p, x)
94+
@test MP.coefficient_type(pi) == Rational{Int}
95+
96+
p = (1.0 * x^2 + 2.0 * y^2)
97+
@test MP.coefficient_type(p) == Float64
98+
99+
pi = DynamicPolynomials.antidifferentiate(p, x)
100+
@test MP.coefficient_type(pi) == Float64
101+
102+
p = 2 * y
103+
pi = DynamicPolynomials.antidifferentiate(p, y)
104+
@test pi == y^2
105+
106+
p = x^2
107+
pi = DynamicPolynomials.antidifferentiate(p, y)
108+
@test pi == x^2 * y
109+
110+
end
111+
84112
@testset "Evaluation" begin
85113
@polyvar x y
86114
@test (x^2 + y^3)(2, 3) == 31

0 commit comments

Comments
 (0)