Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions REQUIRE
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ julia 0.6
Compat 0.49.0
Calculus
NaNMath
SpecialFunctions 0.7
2 changes: 1 addition & 1 deletion src/DualNumbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ __precompile__()

module DualNumbers

using Compat
using Compat, SpecialFunctions
import NaNMath
import Calculus

Expand Down
27 changes: 22 additions & 5 deletions src/dual.jl
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ function Base.angle(z::Dual{Complex{T}}) where T<:Real
end
end

Base.flipsign(x::Dual,y::Dual) = y == 0 ? flipsign(x, epsilon(y)) : flipsign(x, value(y))
Base.flipsign(x, y::Dual) = y == 0 ? flipsign(x, epsilon(y)) : flipsign(x, value(y))
Base.flipsign(x::Dual, y) = dual(flipsign(value(x), y), flipsign(epsilon(x), y))

# algebraic definitions
conjdual(z::Dual) = Dual(value(z),-epsilon(z))
absdual(z::Dual) = abs(value(z))
Expand Down Expand Up @@ -264,6 +268,8 @@ Base.:^(z::Dual, n::Number) = Dual(value(z)^n, epsilon(z)*n*value(z)^(n-1))
NaNMath.pow(z::Dual, n::Number) = Dual(NaNMath.pow(value(z),n), epsilon(z)*n*NaNMath.pow(value(z),n-1))
NaNMath.pow(z::Number, w::Dual) = Dual(NaNMath.pow(z,value(w)), epsilon(w)*NaNMath.pow(z,value(w))*log(z))

inv(z::Dual) = dual(inv(value(z)),-epsilon(z)/value(z)^2)

# force use of NaNMath functions in derivative calculations
function to_nanmath(x::Expr)
if x.head == :call
Expand All @@ -275,14 +281,25 @@ function to_nanmath(x::Expr)
end
to_nanmath(x) = x




for (funsym, exp) in Calculus.symbolic_derivatives_1arg()
funsym == :exp && continue
funsym == :abs2 && continue
isdefined(Base, funsym) || continue
@eval function Base.$(funsym)(z::Dual)
x = value(z)
xp = epsilon(z)
Dual($(funsym)(x),xp*$exp)
funsym == :inv && continue
if isdefined(SpecialFunctions, funsym)
@eval function SpecialFunctions.$(funsym)(z::Dual)
x = value(z)
xp = epsilon(z)
Dual($(funsym)(x),xp*$exp)
end
elseif isdefined(Base, funsym)
@eval function Base.$(funsym)(z::Dual)
x = value(z)
xp = epsilon(z)
Dual($(funsym)(x),xp*$exp)
end
end
# extend corresponding NaNMath methods
if funsym in (:sin, :cos, :tan, :asin, :acos, :acosh, :atanh, :log, :log2, :log10,
Expand Down
19 changes: 18 additions & 1 deletion test/automatic_differentiation_test.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using DualNumbers
using DualNumbers, SpecialFunctions
using Compat
using Compat.Test
using Compat.LinearAlgebra
Expand Down Expand Up @@ -106,6 +106,10 @@ a = angle(z)

@test angle(Dual(0.0+im,0.0+im)) == π/2


# check bug in inv
@test inv(dual(1.0+1.0im,1.0)) == 1/dual(1.0+1.0im,1.0) == dual(1.0+1.0im,1.0)^(-1)

#
# Tests limit definition. Let z = a + b ɛ, where a and b ∈ C.
#
Expand Down Expand Up @@ -145,3 +149,16 @@ test(x, y) = x^2 + y

@test epsilon(Dual(-2.0,1.0)^2.0) == -4
@test epsilon(Dual(-2.0,1.0)^Dual(2.0,0.0)) == -4


# test for flipsign
flipsign(Dual(1.0,1.0),2.0) == Dual(1.0,1.0)
flipsign(Dual(1.0,1.0),-2.0) == Dual(-1.0,-1.0)
flipsign(Dual(1.0,1.0),Dual(1.0,1.0)) == Dual(1.0,1.0)
flipsign(Dual(1.0,1.0),Dual(0.0,-1.0)) == Dual(-1.0,-1.0)
flipsign(-1.0,Dual(1.0,1.0)) == -1.0


# test SpecialFunctions
@test erf(dual(1.0,1.0)) == dual(erf(1.0), 2exp(-1.0^2)/sqrt(π))
@test gamma(dual(1.,1)) == dual(gamma(1.0),polygamma(0,1.0))