diff --git a/.gitignore b/.gitignore index 77805f8a..004ca756 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ docs/build/ docs/site/ benchmark_data/ +Manifest.toml diff --git a/.travis.yml b/.travis.yml index 0f288c9d..67ef7454 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,9 +10,9 @@ notifications: sudo: false script: - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi - - julia -e 'Pkg.clone(pwd()); Pkg.build("ForwardDiff"); Pkg.test("ForwardDiff"; coverage=true)'; - - julia -O3 -e 'include("test/SIMDTest.jl")'; + - julia --color=yes -e 'using Pkg; Pkg.build("ForwardDiff"); Pkg.test("ForwardDiff"; coverage=true)'; + - julia --color=yes -O3 -e 'include("test/SIMDTest.jl")'; after_success: - - julia -e 'Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())' - - julia -e 'Pkg.add("Documenter")' - - julia -e 'include("docs/make.jl")' + - julia --color=yes -e 'using Pkg; Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())' + - julia --color=yes -e 'using Pkg; Pkg.add("Documenter")' + - julia --color=yes -e 'include("docs/make.jl")' diff --git a/Project.toml b/Project.toml new file mode 100644 index 00000000..37cbc283 --- /dev/null +++ b/Project.toml @@ -0,0 +1,21 @@ +name = "ForwardDiff" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "0.8.0" + +[deps] +CommonSubexpressions = "bbf7d656-a473-5ed7-a52c-81e309532950" +DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +DiffRules = "b552c78f-8df3-52c6-915a-8e097449b14b" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[compat] +CommonSubexpressions = "0.1.0" +DiffResults = "0.0.1" +DiffRules = "0.0.4" +NaNMath = "0.2.2" +SpecialFunctions = "0.1.0" +StaticArrays = "0.8.2" diff --git a/appveyor.yml b/appveyor.yml index ac357add..4aae0882 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,9 @@ environment: - JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe" - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe" - JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe" + global: + JULIA_PROJECT: "@." + # as in https://github.com/travis-ci/travis-build/blob/5aef38fe4785caf3fec7a53364e6c17501c8fbb9/lib/travis/build/script/julia.rb#L23 matrix: allow_failures: @@ -34,7 +37,7 @@ build_script: # Need to convert from shallow to complete for Pkg.clone to work - IF EXIST .git\shallow (git fetch --unshallow) - C:\projects\julia\bin\julia -e "versioninfo(); - Pkg.clone(pwd(), \"ForwardDiff\"); Pkg.build(\"ForwardDiff\")" + using Pkg; Pkg.build(\"ForwardDiff\")" test_script: - - C:\projects\julia\bin\julia -e "Pkg.test(\"ForwardDiff\")" + - C:\projects\julia\bin\julia -e "using Pkg; Pkg.test(\"ForwardDiff\")" diff --git a/src/dual.jl b/src/dual.jl index 831b9cc2..c8db0354 100644 --- a/src/dual.jl +++ b/src/dual.jl @@ -425,6 +425,18 @@ for f in (:(Base.:^), :(NaNMath.pow)) end end +@inline Base.literal_pow(::typeof(^), x::Dual{T}, ::Val{0}) where {T} = + Dual{T}(one(value(x)), zero(partials(x))) + +for y in 1:3 + @eval @inline function Base.literal_pow(::typeof(^), x::Dual{T}, ::Val{$y}) where {T} + v = value(x) + expv = v^$y + deriv = $y * v^$(y - 1) + return Dual{T}(expv, deriv * partials(x)) + end +end + # hypot # #-------# diff --git a/test/DualTest.jl b/test/DualTest.jl index 75041ded..d7941b9b 100644 --- a/test/DualTest.jl +++ b/test/DualTest.jl @@ -460,9 +460,10 @@ end x1 = Dual{:t1}(x0, 1.0) x2 = Dual{:t2}(x1, 1.0) x3 = Dual{:t3}(x2, 1.0) - @test x3^2 === x3 * x3 - @test x2^1 === x2 - @test x1^0 === Dual{:t1}(1.0, 0.0) + pow = ^ # to call non-literal power + @test pow(x3, 2) === x3^2 === x3 * x3 + @test pow(x2, 1) === x2^1 === x2 + @test pow(x1, 0) === x1^0 === Dual{:t1}(1.0, 0.0) end end # module diff --git a/test/SIMDTest.jl b/test/SIMDTest.jl index ec34e811..fc9fa2f5 100644 --- a/test/SIMDTest.jl +++ b/test/SIMDTest.jl @@ -3,6 +3,7 @@ module SIMDTest using Test using ForwardDiff: Dual, valtype using InteractiveUtils: code_llvm +using StaticArrays: SVector const DUALS = (Dual(1., 2., 3., 4.), Dual(1., 2., 3., 4., 5.), @@ -17,7 +18,7 @@ function simd_sum(x::Vector{T}) where T return s end -for D in map(typeof, DUALS) +@testset "SIMD $D" for D in map(typeof, DUALS) plus_bitcode = sprint(io -> code_llvm(io, +, (D, D))) @test occursin("fadd <4 x double>", plus_bitcode) @@ -32,6 +33,9 @@ for D in map(typeof, DUALS) @test occursin(r"fadd \<.*?x double\>", div_bitcode) @test occursin(r"fmul \<.*?x double\>", div_bitcode) + pow_bitcode = sprint(io -> code_llvm(io, ^, (D, Int))) + @test occursin(r"fmul \<.*?x double\>", pow_bitcode) + exp_bitcode = sprint(io -> code_llvm(io, ^, (D, D))) @test occursin(r"fadd \<.*?x double\>", exp_bitcode) if !(valtype(D) <: Dual) @@ -44,4 +48,26 @@ for D in map(typeof, DUALS) end end +# `pow2dot` is chosen so that `@code_llvm pow2dot(SVector(1:1.0:4...))` +# generates code with SIMD instructions. +# See: +# https://github.com/JuliaDiff/ForwardDiff.jl/pull/332 +# https://github.com/JuliaDiff/ForwardDiff.jl/pull/331#issuecomment-406107260 +@inline pow2(x) = x^2 +pow2dot(xs) = pow2.(xs) + +# Nested dual such as `Dual(Dual(1., 2.), Dual(3., 4.))` only produces +# "fmul <2 x double>" so it is excluded from the following test. +const POW_DUALS = (Dual(1., 2.), + Dual(1., 2., 3.), + Dual(1., 2., 3., 4.), + Dual(1., 2., 3., 4., 5.)) + +@testset "SIMD square of $D" for D in map(typeof, POW_DUALS) + pow_bitcode = sprint(io -> code_llvm(io, pow2dot, (SVector{4, D},))) + @test occursin(r"(.*fmul \<4 x double\>){2}"s, pow_bitcode) + # "{2}" is for asserting that fmul has to appear at least twice: + # once for `.value` and once for `.partials`. +end + end # module