|
| 1 | +export antidifferentiate |
| 2 | + |
| 3 | +""" |
| 4 | + antidifferentiate(p::AbstractPolynomialLike, v::AbstractVariable, deg::Union{Int, Val}=1) |
| 5 | +
|
| 6 | +Antidifferentiate `deg` times the polynomial `p` by the variable `v`. The free constant involved by |
| 7 | +the antidifferentiation is set to 0. |
| 8 | +
|
| 9 | +
|
| 10 | + antidifferentiate(p::AbstractPolynomialLike, vs, deg::Union{Int, Val}=1) |
| 11 | +
|
| 12 | +Antidifferentiate `deg` times the polynomial `p` by the variables of the vector or |
| 13 | +tuple of variable `vs` and return an array of dimension `deg`. It is recommended |
| 14 | +to pass `deg` as a `Val` instance when the degree is known at compile time, e.g. |
| 15 | +`antidifferentiate(p, v, Val{2}())` instead of `antidifferentiate(p, x, 2)`, as this |
| 16 | +will help the compiler infer the return type. |
| 17 | +
|
| 18 | +### Examples |
| 19 | +
|
| 20 | +```julia |
| 21 | +p = 3x^2*y + x + 2y + 1 |
| 22 | +antidifferentiate(p, x) # should return 3x^3* + 1/2*x + 2xy + x |
| 23 | +antidifferentiate(p, x, Val{1}()) # equivalent to the above |
| 24 | +antidifferentiate(p, (x, y)) # should return [3x^3* + 1/2*x + 2xy + x, 3/2x^2*y^2 + xy + y^2 + y] |
| 25 | +``` |
| 26 | +""" |
| 27 | +function antidifferentiate end |
| 28 | + |
| 29 | +# Fallback for everything else |
| 30 | +antidifferentiate(α::T, v::AbstractVariable) where {T} = α * v |
| 31 | +antidifferentiate(v1::AbstractVariable, v2::AbstractVariable) = v1 == v2 ? 1 // 2 * v1 * v2 : v1 * v2 |
| 32 | +antidifferentiate(t::AbstractTermLike, v::AbstractVariable) = coefficient(t) * antidifferentiate(monomial(t), v) |
| 33 | +antidifferentiate(p::APL, v::AbstractVariable) = polynomial!(antidifferentiate.(terms(p), v), SortedState()) |
| 34 | + |
| 35 | +# TODO: this signature is probably too wide and creates the potential |
| 36 | +# for stack overflows |
| 37 | +antidifferentiate(p::APL, xs) = [antidifferentiate(p, x) for x in xs] |
| 38 | + |
| 39 | +# antidifferentiate(p, [x, y]) with TypedPolynomials promote x to a Monomial |
| 40 | +antidifferentiate(p::APL, m::AbstractMonomial) = antidifferentiate(p, variable(m)) |
| 41 | + |
| 42 | +# The `R` argument indicates a desired result type. We use this in order |
| 43 | +# to attempt to preserve type-stability even though the value of `deg` cannot |
| 44 | +# be known at compile time. For scalar `p` and `x`, we set R to be the type |
| 45 | +# of antidifferentiate(p, x) to give a stable result type regardless of `deg`. For |
| 46 | +# vectors p and/or x this is impossible (since antidifferentiate may return an array), |
| 47 | +# so we just set `R` to `Any` |
| 48 | +function (_antidifferentiate_recursive(p, x, deg::Int, ::Type{R})::R) where {R} |
| 49 | + if deg < 0 |
| 50 | + throw(DomainError(deg, "degree is negative")) |
| 51 | + elseif deg == 0 |
| 52 | + return p |
| 53 | + else |
| 54 | + return antidifferentiate(antidifferentiate(p, x), x, deg - 1) |
| 55 | + end |
| 56 | +end |
| 57 | + |
| 58 | +antidifferentiate(p, x, deg::Int) = _antidifferentiate_recursive(p, x, deg, Base.promote_op(antidifferentiate, typeof(p), typeof(x))) |
| 59 | +antidifferentiate(p::AbstractArray, x, deg::Int) = _antidifferentiate_recursive(p, x, deg, Any) |
| 60 | +antidifferentiate(p, x::Union{AbstractArray,Tuple}, deg::Int) = _antidifferentiate_recursive(p, x, deg, Any) |
| 61 | +antidifferentiate(p::AbstractArray, x::Union{AbstractArray,Tuple}, deg::Int) = _antidifferentiate_recursive(p, x, deg, Any) |
| 62 | + |
| 63 | + |
| 64 | +# This is alternative, Val-based interface for nested antidifferentiation. |
| 65 | +# It has the advantage of not requiring an conversion or calls to |
| 66 | +# Base.promote_op, while maintaining type stability for any argument |
| 67 | +# type. |
| 68 | +antidifferentiate(p, x, ::Val{0}) = p |
| 69 | +antidifferentiate(p, x, ::Val{1}) = antidifferentiate(p, x) |
| 70 | + |
| 71 | +function antidifferentiate(p, x, deg::Val{N}) where {N} |
| 72 | + if N < 0 |
| 73 | + throw(DomainError(deg)) |
| 74 | + else |
| 75 | + antidifferentiate(antidifferentiate(p, x), x, Val{N - 1}()) |
| 76 | + end |
| 77 | +end |
0 commit comments