diff --git a/.travis.yml b/.travis.yml index 8bf16fe6..69b0bf6b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: julia julia: - - 0.5 - 0.6 - nightly notifications: diff --git a/REQUIRE b/REQUIRE index 3809d461..7f2f5e18 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,6 +1,5 @@ -julia 0.5 +julia 0.6- DiffBase 0.0.3 -Compat 0.19.0 Calculus 0.2.0 NaNMath 0.2.2 SpecialFunctions 0.1.0 diff --git a/benchmark/ForwardDiffBenchmarks.jl b/benchmarks/benchmarks.jl similarity index 91% rename from benchmark/ForwardDiffBenchmarks.jl rename to benchmarks/benchmarks.jl index 88312f5c..75523594 100644 --- a/benchmark/ForwardDiffBenchmarks.jl +++ b/benchmarks/benchmarks.jl @@ -1,5 +1,3 @@ -module ForwardDiffBenchmarks - using ForwardDiff, DiffBase using BenchmarkTools @@ -39,11 +37,11 @@ for f in (DiffBase.VECTOR_TO_NUMBER_FUNCS..., DiffBase.MATRIX_TO_NUMBER_FUNCS... fval[length(x)] = @benchmarkable $(f)($x) gout = DiffBase.DiffResult(y, similar(x, typeof(y))) - gcfg = ForwardDiff.Config(x) + gcfg = ForwardDiff.GradientConfig(nothing, x) fgrad[length(x)] = @benchmarkable ForwardDiff.gradient!($gout, $f, $x, $gcfg) hout = DiffBase.DiffResult(y, similar(x, typeof(y)), similar(x, typeof(y), length(x), length(x))) - hcfg = ForwardDiff.HessianConfig(hout, x) + hcfg = ForwardDiff.HessianConfig(nothing, hout, x) fhess[length(x)] = @benchmarkable ForwardDiff.hessian!($hout, $f, $x, $hcfg) end end @@ -56,9 +54,7 @@ for f in DiffBase.ARRAY_TO_ARRAY_FUNCS fval[length(x)] = @benchmarkable $(f)($x) out = DiffBase.JacobianResult(y, x) - cfg = ForwardDiff.Config(x) - fjac[length(x)] = @benchmarkable ForwardDiff.jacobian!($out, $f, $x, $cfg) + cfg = ForwardDiff.JacobianConfig(nothing, y, x) + fjac[length(x)] = @benchmarkable ForwardDiff.jacobian!($out, $f, $y, $x, $cfg) end end - -end # module diff --git a/benchmark/cpp/.gitignore b/benchmarks/cpp/.gitignore similarity index 100% rename from benchmark/cpp/.gitignore rename to benchmarks/cpp/.gitignore diff --git a/benchmark/cpp/Makefile b/benchmarks/cpp/Makefile similarity index 100% rename from benchmark/cpp/Makefile rename to benchmarks/cpp/Makefile diff --git a/benchmark/cpp/benchmarks.cpp b/benchmarks/cpp/benchmarks.cpp similarity index 100% rename from benchmark/cpp/benchmarks.cpp rename to benchmarks/cpp/benchmarks.cpp diff --git a/benchmark/cpp/benchmarks.h b/benchmarks/cpp/benchmarks.h similarity index 100% rename from benchmark/cpp/benchmarks.h rename to benchmarks/cpp/benchmarks.h diff --git a/benchmark/cpp/dual1.cpp b/benchmarks/cpp/dual1.cpp similarity index 100% rename from benchmark/cpp/dual1.cpp rename to benchmarks/cpp/dual1.cpp diff --git a/benchmark/cpp/dual2.cpp b/benchmarks/cpp/dual2.cpp similarity index 100% rename from benchmark/cpp/dual2.cpp rename to benchmarks/cpp/dual2.cpp diff --git a/benchmark/cpp/dual3.cpp b/benchmarks/cpp/dual3.cpp similarity index 100% rename from benchmark/cpp/dual3.cpp rename to benchmarks/cpp/dual3.cpp diff --git a/benchmark/cpp/dual4.cpp b/benchmarks/cpp/dual4.cpp similarity index 100% rename from benchmark/cpp/dual4.cpp rename to benchmarks/cpp/dual4.cpp diff --git a/benchmark/cpp/dual5.cpp b/benchmarks/cpp/dual5.cpp similarity index 100% rename from benchmark/cpp/dual5.cpp rename to benchmarks/cpp/dual5.cpp diff --git a/benchmark/py/algopy_benchmarks.py b/benchmarks/py/algopy_benchmarks.py similarity index 100% rename from benchmark/py/algopy_benchmarks.py rename to benchmarks/py/algopy_benchmarks.py diff --git a/benchmark/py/autograd_benchmarks.py b/benchmarks/py/autograd_benchmarks.py similarity index 100% rename from benchmark/py/autograd_benchmarks.py rename to benchmarks/py/autograd_benchmarks.py diff --git a/docs/_rst/source/advanced_usage.rst b/docs/_rst/source/advanced_usage.rst index 576cc4ee..df0c887d 100644 --- a/docs/_rst/source/advanced_usage.rst +++ b/docs/_rst/source/advanced_usage.rst @@ -9,7 +9,7 @@ Accessing Lower-Order Results Let's say you want to calculate the value, gradient, and Hessian of some function ``f`` at an input ``x``. You could execute ``f(x)``, ``ForwardDiff.gradient(f, x)`` and -``ForwardDiff.hessian(f, x)``, but that would be a **horribly redundant way to accomplish +``ForwardDiff.hessian(f, x)``, but that would be a **horribly redundant way to accomplish this task!** In the course of calculating higher-order derivatives, ForwardDiff ends up calculating all @@ -37,7 +37,7 @@ For example: .. code-block:: julia - julia> import ForwardDiff + julia> using ForwardDiff: GradientConfig, Chunk, gradient! # let's use a Rosenbrock function as our target function julia> function rosenbrock(x) @@ -58,25 +58,25 @@ For example: julia> out = similar(x); # construct GradientConfig with chunk size of 1 - julia> cfg1 = ForwardDiff.GradientConfig{1}(x); + julia> cfg1 = GradientConfig(rosenbrock, x, Chunk{1}()); # construct GradientConfig with chunk size of 4 - julia> cfg4 = ForwardDiff.GradientConfig{4}(x); + julia> cfg4 = GradientConfig(rosenbrock, x, Chunk{4}()); # construct GradientConfig with chunk size of 10 - julia> cfg10 = ForwardDiff.GradientConfig{10}(x); + julia> cfg10 = GradientConfig(rosenbrock, x, Chunk{10}()); # (input length of 10000) / (chunk size of 1) = (10000 1-element chunks) - julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg1); - 0.408305 seconds (4 allocations: 160 bytes) + julia> @time gradient!(out, rosenbrock, x, cfg1); + 0.775139 seconds (4 allocations: 160 bytes) # (input length of 10000) / (chunk size of 4) = (2500 4-element chunks) - julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg4); - 0.295764 seconds (4 allocations: 160 bytes) + julia> @time gradient!(out, rosenbrock, x, cfg4); + 0.386459 seconds (4 allocations: 160 bytes) # (input length of 10000) / (chunk size of 10) = (1000 10-element chunks) - julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg10); - 0.267396 seconds (4 allocations: 160 bytes) + julia> @time gradient!(out, rosenbrock, x, cfg10); + 0.282529 seconds (4 allocations: 160 bytes) If you do not explicity provide a chunk size, ForwardDiff will try to guess one for you based on your input vector: @@ -85,10 +85,10 @@ based on your input vector: # The GradientConfig constructor will automatically select a # chunk size in one is not explicitly provided - julia> cfg = ForwardDiff.GradientConfig(x); + julia> cfg = ForwardDiff.GradientConfig(rosenbrock, x); julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg); - 0.266920 seconds (4 allocations: 160 bytes) + 0.281853 seconds (4 allocations: 160 bytes) If your input dimension is a constant, you should explicitly select a chunk size rather than relying on ForwardDiff's heuristic. There are two reasons for this. The first is that @@ -130,8 +130,8 @@ aren't sensitive to the input and thus cause ForwardDiff to incorrectly return ` # the dual number's perturbation component is zero, so this # variable should not propagate derivative information - julia> log(ForwardDiff.Dual(0.0, 0.0)) - Dual(-Inf,NaN) # oops, this NaN should be 0.0 + julia> log(ForwardDiff.Dual{:tag}(0.0, 0.0)) + Dual{:tag}(-Inf,NaN) # oops, this NaN should be 0.0 Here, ForwardDiff computes the derivative of ``log(0.0)`` as ``NaN`` and then propagates this derivative by multiplying it by the perturbation component. Usually, ForwardDiff can @@ -153,7 +153,6 @@ In the future, we plan on allowing users and downstream library authors to dynam enable ``NaN``-safe mode via the ``AbstractConfig`` API (see `the relevant issue `_). - Hessian of a vector-valued function ----------------------------------- @@ -163,17 +162,17 @@ For example: .. code-block:: julia - julia> ForwardDiff.jacobian(x -> ForwardDiff.jacobian(sin, x), [1,2,3]) - 9×3 Array{Float64,2}: - -0.841471 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.0 - 0.0 0.0 0.0 - -0.0 -0.909297 -0.0 - -0.0 -0.0 -0.0 - 0.0 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.14112 + julia> ForwardDiff.jacobian(x -> ForwardDiff.jacobian(cumprod, x), [1,2,3]) + 9×3 Array{Int64,2}: + 0 0 0 + 0 1 0 + 0 3 2 + 0 0 0 + 1 0 0 + 3 0 1 + 0 0 0 + 0 0 0 + 2 1 0 Since this functionality is composed from ForwardDiff's existing API rather than built into it, you're free to construct a ``vector_hessian`` function which suits your needs. For @@ -190,22 +189,22 @@ expensive operation): end vector_hessian (generic function with 1 method) - julia> vector_hessian(sin, [1, 2, 3]) - 3×3×3 Array{Float64,3}: + julia> vector_hessian(cumprod, [1, 2, 3]) + 3×3×3 Array{Int64,3}: [:, :, 1] = - -0.841471 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.0 + 0 0 0 + 0 1 0 + 0 3 2 [:, :, 2] = - 0.0 0.0 0.0 - -0.0 -0.909297 -0.0 - -0.0 -0.0 -0.0 + 0 0 0 + 1 0 0 + 3 0 1 [:, :, 3] = - 0.0 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.14112 + 0 0 0 + 0 0 0 + 2 1 0 Likewise, you could write a version of ``vector_hessian`` which supports functions of the form ``f!(y, x)``, or perhaps an in-place Jacobian with ``ForwardDiff.jacobian!``. @@ -232,10 +231,10 @@ SIMD instructions (i.e. not starting Julia with ``-O3``): julia> using ForwardDiff: Dual julia> a = Dual(1., 2., 3., 4.) - Dual(1.0,2.0,3.0,4.0) + Dual{Void}(1.0,2.0,3.0,4.0) julia> b = Dual(5., 6., 7., 8.) - Dual(5.0,6.0,7.0,8.0) + Dual{Void}(5.0,6.0,7.0,8.0) julia> @code_llvm a + b diff --git a/docs/_rst/source/basic_api.rst b/docs/_rst/source/basic_api.rst index 28eb6392..96115abd 100644 --- a/docs/_rst/source/basic_api.rst +++ b/docs/_rst/source/basic_api.rst @@ -4,22 +4,26 @@ Basic ForwardDiff API Derivatives of :math:`f(x) : \mathbb{R} \to \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k}` -------------------------------------------------------------------------------------------------- -Use ``ForwardDiff.derivative`` to differentiate functions of the form ``f(::Real)::Real`` and ``f(::Real)::AbstractArray``. +Use ``ForwardDiff.derivative`` to differentiate functions of the form ``f(::Real...)::Real`` and ``f(::Real...)::AbstractArray``. .. function:: ForwardDiff.derivative!(out, f, x) - Compute :math:`f'(x)`, storing the output in ``out``. + Compute :math:`f'(x)`, storing the output in ``out``. If ``x`` is a ``Tuple``, + then ``f`` will be called as ``f(x...)`` and the derivatives with respect to + each element in `x` will be stored in the respective element of ``out`` (which + should also be a ``Tuple``). .. function:: ForwardDiff.derivative(f, x) - Compute and return :math:`f'(x)`. + Compute and return :math:`f'(x)`. If ``x`` is a ``Tuple``, ``f`` will be + called as ``f(x...)``, and a ``Tuple`` of derivatives will be returned. Gradients of :math:`f(x) : \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k} \to \mathbb{R}` ------------------------------------------------------------------------------------------------ Use ``ForwardDiff.gradient`` to differentiate functions of the form ``f(::AbstractArray)::Real``. -.. function:: ForwardDiff.gradient!(out, f, x, cfg = ForwardDiff.GradientConfig(x)) +.. function:: ForwardDiff.gradient!(out, f, x, cfg = ForwardDiff.GradientConfig(f, x)) Compute :math:`\nabla f(\vec{x})`, storing the output in ``out``. It is highly advised to preallocate ``cfg`` yourself (see the `AbstractConfig @@ -34,23 +38,23 @@ Jacobians of :math:`f(x) : \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k} Use ``ForwardDiff.jacobian`` to differentiate functions of the form ``f(::AbstractArray)::AbstractArray``. -.. function:: ForwardDiff.jacobian!(out, f, x, cfg = ForwardDiff.JacobianConfig(x)) +.. function:: ForwardDiff.jacobian!(out, f, x, cfg = ForwardDiff.JacobianConfig(f, x)) Compute :math:`\mathbf{J}(f)(\vec{x})`, storing the output in ``out``. It is highly advised to preallocate ``cfg`` yourself (see the `AbstractConfig `_ section below). -.. function:: ForwardDiff.jacobian!(out, f!, y, x, cfg = ForwardDiff.JacobianConfig(y, x)) +.. function:: ForwardDiff.jacobian!(out, f!, y, x, cfg = ForwardDiff.JacobianConfig(f!, y, x)) Compute :math:`\mathbf{J}(f)(\vec{x})`, where :math:`f(\vec{x})` can be called as ``f!(y, x)`` such that the output of :math:`f(\vec{x})` is stored in ``y``. The output matrix is stored in ``out``. -.. function:: ForwardDiff.jacobian(f, x, cfg = ForwardDiff.JacobianConfig(x)) +.. function:: ForwardDiff.jacobian(f, x, cfg = ForwardDiff.JacobianConfig(f, x)) Compute and return :math:`\mathbf{J}(f)(\vec{x})`. -.. function:: ForwardDiff.jacobian(f!, y, x, cfg = ForwardDiff.JacobianConfig(y, x)) +.. function:: ForwardDiff.jacobian(f!, y, x, cfg = ForwardDiff.JacobianConfig(f!, y, x)) Compute and return :math:`\mathbf{J}(f)(\vec{x})`, where :math:`f(\vec{x})` can be called as ``f!(y, x)`` such that the output of :math:`f(\vec{x})` is stored in ``y``. @@ -60,13 +64,13 @@ Hessians of :math:`f(x) : \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k} Use ``ForwardDiff.hessian`` to perform second-order differentiation on functions of the form ``f(::AbstractArray)::Real``. -.. function:: ForwardDiff.hessian!(out, f, x, cfg = ForwardDiff.HessianConfig(x)) +.. function:: ForwardDiff.hessian!(out, f, x, cfg = ForwardDiff.HessianConfig(f, x)) Compute :math:`\mathbf{H}(f)(\vec{x})`, storing the output in ``out``. It is highly advised to preallocate ``cfg`` yourself (see the `AbstractConfig `_ section below). -.. function:: ForwardDiff.hessian(f, x, cfg = ForwardDiff.HessianConfig(x)) +.. function:: ForwardDiff.hessian(f, x, cfg = ForwardDiff.HessianConfig(f, x)) Compute and return :math:`\mathbf{H}(f)(\vec{x})`. @@ -77,66 +81,63 @@ For the sake of convenience and performance, all "extra" information used by For API methods is bundled up in the ``ForwardDiff.AbstractConfig`` family of types. Theses types allow the user to easily feed several different parameters to ForwardDiff's API methods, such as `chunk size `_, work buffers, -multithreading configurations, and perturbation seed configurations. +and perturbation seed configurations. ForwardDiff's basic API methods will allocate these types automatically by default, but you can drastically reduce memory usage if you preallocate them yourself. -Note that for all constructors below, the chunk size ``N`` may be explictly provided as a -type parameter, or omitted, in which case ForwardDiff will automatically select a chunk size -for you. However, it is highly recomended to `specify the chunk size manually when possible +Note that for all constructors below, the chunk size ``N`` may be explictly provided, +or omitted, in which case ForwardDiff will automatically select a chunk size for you. +However, it is highly recomended to `specify the chunk size manually when possible `_. -.. function:: ForwardDiff.GradientConfig{N}(x) +Note also that configurations constructed for a specific function ``f`` cannot +be reused to differentiate other functions (though can be reused to differentiate +``f`` at different values). To construct a configuration which can be reused to +differentiate any function, you can pass ``nothing`` as the function argument. +While this is more flexible, this decreases ForwardDiff's ability to catch +and prevent `perturbation confusion`_. - Construct a ``GradientConfig`` instance based on the type and shape of the input vector - ``x``. The returned ``GradientConfig`` instance contains all the work buffers required - by ForwardDiff's gradient/Jacobian methods. If taking the Jacobian of a target function - with the form ``f!(y, x)``, use the constructor ``ForwardDiff.GradientConfig{N}(y, x)`` - instead. +.. function:: ForwardDiff.GradientConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) + + Construct a ``GradientConfig`` instance based on the type of ``f`` and + type/shape of the input vector ``x``. The returned ``GradientConfig`` + instance contains all the work buffers required by ForwardDiff's gradient + methods. This constructor does not store/modify ``x``. -.. function:: ForwardDiff.JacobianConfig{N}(x) +.. function:: ForwardDiff.JacobianConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Exactly like ``ForwardDiff.GradientConfig{N}(x)``, but returns a `JacobianConfig` - instead. + Exactly like the ``GradientConfig`` constructor, but returns a ``JacobianConfig`` instead. -.. function:: ForwardDiff.JacobianConfig{N}(y, x) +.. function:: ForwardDiff.JacobianConfig(f!, y, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Construct a ``JacobianConfig`` instance based on the type and shape of the output vector - ``y`` and the input vector ``x``. The returned ``JacobianConfig`` instance contains all - the work buffers required by ``ForwardDiff.jacobian``/``ForwardDiff.jacobian!`` with a - target function of the form ``f!(y, x)``. + Construct a ``JacobianConfig`` instance based on the type of ``f!``, and the + types/shapes of the output vector ``y`` and the input vector ``x``. The + returned ``JacobianConfig`` instance contains all the work buffers required + by ``ForwardDiff.jacobian``/``ForwardDiff.jacobian!`` when the target + function takes the form ``f!(y, x)``. This constructor does not store/modify ``y`` or ``x``. -.. function:: ForwardDiff.HessianConfig{N}(x) +.. function:: ForwardDiff.HessianConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Construct a ``HessianConfig`` instance based on the type and shape of the input vector - ``x``. The returned ``HessianConfig`` instance contains all the work buffers required - by ForwardDiff's Hessian methods. If using - ``ForwardDiff.hessian!(out::DiffBase.DiffResult, args...)``, use the constructor - ``ForwardDiff.HessianConfig{N}(out, x)`` instead. + Construct a ``HessianConfig`` instance based on the type of ``f`` and + type/shape of the input vector ``x``. The returned ``HessianConfig`` instance contains + all the work buffers required by ForwardDiff's Hessian methods. If using + ``ForwardDiff.hessian!(out::DiffBase.DiffResult, f, x)``, use the constructor + ``ForwardDiff.HessianConfig(f, out, x, chunk)`` instead. This constructor does not store/modify ``x``. -.. function:: ForwardDiff.HessianConfig{N}(out::DiffBase.DiffResult, x) +.. function:: ForwardDiff.HessianConfig(f, out::DiffBase.DiffResult, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Construct an ``HessianConfig`` instance based on the type and shape of the storage in - ``out`` and the input vector ``x``. The returned ``HessianConfig`` instance contains - all the work buffers required by ``ForwardDiff.hessian!(out::DiffBase.DiffResult, - args...)``. + Construct an ``HessianConfig`` instance based on the type of ``f``, types/storage + in ``out``, and type/shape of the input vector ``x``. The returned ``HessianConfig`` + instance contains all the work buffers required by + ``ForwardDiff.hessian!(out::DiffBase.DiffResult, args...)``. This constructor does not store/modify ``out`` or ``x``. -.. function:: ForwardDiff.MultithreadConfig(cfg::AbstractConfig) - - Wrap the given ``cfg`` in a ``MultithreadConfig`` instance, which can then be passed to - gradient or Hessian methods in order to enable experimental multithreading. Jacobian - methods do not yet support multithreading. - - Note that multithreaded ForwardDiff API methods will attempt to use all available - threads. In the future, once Julia exposes more fine-grained threading primitives, - a ``MultithreadConfig`` constructor may be added which takes in a user-provided subset - of thread IDs instead of using all available threads. +.. _`perturbation confusion`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/83 diff --git a/docs/_rst/source/conf.py b/docs/_rst/source/conf.py index 0f4ba663..6e45536b 100644 --- a/docs/_rst/source/conf.py +++ b/docs/_rst/source/conf.py @@ -57,9 +57,9 @@ # built documents. # # The short X.Y version. -version = '0.2' +version = '0.5' # The full version, including alpha/beta/rc tags. -release = '0.2.3' +release = '0.5.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/_rst/source/contributing.rst b/docs/_rst/source/contributing.rst index cb669228..7de30bdc 100644 --- a/docs/_rst/source/contributing.rst +++ b/docs/_rst/source/contributing.rst @@ -40,9 +40,7 @@ To see a list of functions to pick from, look at ``ForwardDiff.AUTO_DEFINED_UNAR ⋮ Some of these functions may have already been manually optimized. To see what functions have -already been done, go to ``src/dual.jl``, scroll down to the ``Special Cases`` section, and -look at the functions under ``Manually Optimized`` (further optimizations to these functions -are always welcome, if you can come up with something clever). +already been done, go to ``src/dual.jl`` and scroll down to the ``Special Cases`` section. The functions in ``ForwardDiff.AUTO_DEFINED_UNARY_FUNCS`` are automatically tested as part of ForwardDiff's test suite, so you don't need to write tests yourself. You can test your diff --git a/docs/_rst/source/how_it_works.rst b/docs/_rst/source/how_it_works.rst index 20a96e49..dd8114cb 100644 --- a/docs/_rst/source/how_it_works.rst +++ b/docs/_rst/source/how_it_works.rst @@ -9,25 +9,26 @@ Julia. There are two key components of this implementation: the ``Dual`` type, a Dual Number Implementation -------------------------- -Partial derivatives are stored in the ``Partials{N,T}`` type: +Partial derivatives are stored in the ``Partials{N,V}`` type: .. code-block:: julia - immutable Partials{N,T} - values::NTuple{N,T} + struct Partials{N,V} <: AbstractVector{V} + values::NTuple{N,V} end -Overtop of this container type, ForwardDiff implements the ``Dual{N,T}`` type: +Overtop of this container type, ForwardDiff implements the ``Dual{T,V,N}`` type: .. code-block:: julia - immutable Dual{N,T<:Real} <: Real - value::T - partials::Partials{N,T} + struct Dual{T,V<:Real,N} <: Real + value::V + partials::Partials{N,V} end -This type represents an ``N``-dimensional `dual number`_ with the following mathematical -behavior: +This type represents an ``N``-dimensional `dual number`_ coupled with a tag +parameter `T` in order to prevent `perturbation confusion`_. This dual number +type is implemented to have the following mathematical behavior: .. math:: @@ -44,22 +45,23 @@ can be overloaded on ``Dual`` like so: .. code-block:: julia - Base.sin(d::Dual) = Dual(sin(value(d)), cos(value(d)) * partials(d)) + Base.sin(d::Dual{T}) where {T} = Dual{T}(sin(value(d)), cos(value(d)) * partials(d)) If we assume that a general function ``f`` is composed of entirely of these elementary functions, then the chain rule enables our derivatives to compose as well. Thus, by overloading a plethora of elementary functions, we can differentiate generic functions composed of them by passing in a ``Dual`` number and looking at the output. -We won't dicuss higher-order differentiation in detail, but the reader is encouraged to +We won't discuss higher-order differentiation in detail, but the reader is encouraged to learn about `hyper-dual numbers`_, which extend dual numbers to higher orders by introducing extra :math:`\epsilon` terms that can cross-multiply. ForwardDiff's ``Dual`` number implementation naturally supports hyper-dual numbers without additional code by allowing instances of the ``Dual`` type to nest within each other. For example, a second-order -hyper-dual number has the type ``Dual{N,Dual{N,T}}``, a third-order hyper-dual number has -the type ``Dual{N,Dual{N,Dual{N,T}}}``, and so on. +hyper-dual number has the type ``Dual{T,Dual{S,V,M},N}``, a third-order hyper-dual number has +the type ``Dual{T,Dual{S,Dual{R,V,K},M},N}``, and so on. .. _`dual number`: https://en.wikipedia.org/wiki/Dual_number +.. _`perturbation confusion`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/83 .. _`hyper-dual numbers`: https://adl.stanford.edu/hyperdual/Fike_AIAA-2011-886.pdf ForwardDiff's API diff --git a/docs/_rst/source/install.rst b/docs/_rst/source/install.rst index bb7668d6..4f3573b6 100644 --- a/docs/_rst/source/install.rst +++ b/docs/_rst/source/install.rst @@ -7,4 +7,4 @@ To install ForwardDiff, simply use Julia's package manager: julia> Pkg.add("ForwardDiff") -The current version of ForwardDiff supports Julia v0.4 and v0.5. +The current version of ForwardDiff supports Julia v0.6. diff --git a/docs/_rst/source/limitations.rst b/docs/_rst/source/limitations.rst index 9862d12b..65ecb75a 100644 --- a/docs/_rst/source/limitations.rst +++ b/docs/_rst/source/limitations.rst @@ -12,10 +12,7 @@ function being differentiated): - **The target function must be written generically enough to accept numbers of type ``T<:Real`` as input (or arrays of these numbers).** The function doesn't require a specific type signature, as long as the type signature is generic enough to avoid breaking this rule. This also means that any storage assigned used within the function must be generic as well (see `this comment`_ for an example). -- **Nested differentiation of closures is dangerous.** Differentiating closures is safe, and nested differentation is safe, but you might be vulnerable to a subtle bug if you try to do both. See `the relevant issue`_ for details. - - **The types of array inputs must be subtypes of** ``AbstractArray`` **.** Non-``AbstractArray`` array-like types are not officially supported. .. _`this comment`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/136#issuecomment-237941790 -.. _`the relevant issue`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/83 .. _`this file`: https://github.com/JuliaDiff/ForwardDiff.jl/blob/master/src/cache.jl diff --git a/docs/_rst/source/upgrade.rst b/docs/_rst/source/upgrade.rst index 5fc2ef82..a0afb6af 100644 --- a/docs/_rst/source/upgrade.rst +++ b/docs/_rst/source/upgrade.rst @@ -14,11 +14,11 @@ functions to reference them: .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 using ForwardDiff hessian(f, x) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above using ForwardDiff ForwardDiff.hessian(f, x) @@ -27,26 +27,32 @@ Setting Chunk Size .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 ForwardDiff.gradient(f, x; chunk_size = 10) - # old v0.2 style + # ForwardDiff v0.2 ForwardDiff.gradient(f, x, Chunk{10}()) - # current v0.3 style + # ForwardDiff v0.3 & v0.4 ForwardDiff.gradient(f, x, ForwardDiff.GradientConfig{10}(x)) + # ForwardDiff v0.5 & above + ForwardDiff.gradient(f, x, ForwardDiff.GradientConfig(f, x ForwardDiff.Chunk{N}())) + Enabling Multithreading ----------------------- .. code-block:: julia - # old v0.1/v0.2 style + # ForwardDiff v0.1 & v0.2 ForwardDiff.gradient(f, x; multithread = true) - # current v0.3 style + # ForwardDiff v0.3 & v0.4 ForwardDiff.gradient(f, x, ForwardDiff.MultithreadConfig(ForwardDiff.GradientConfig(x))) + # ForwardDiff v0.5 & above + error("ForwardDiff no longer supports internal multithreading.") + Retrieving Lower-Order Results ------------------------------ @@ -55,20 +61,20 @@ For more detail, see our documentation on `retrieving lower-order results .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 answer, results = ForwardDiff.hessian(f, x, AllResults) v = ForwardDiff.value(results) g = ForwardDiff.gradient(results) h = ForwardDiff.hessian(results) # == answer - # old v0.2 style + # ForwardDiff v0.2 out = HessianResult(x) ForwardDiff.hessian!(out, f, x) v = ForwardDiff.value(out) g = ForwardDiff.gradient(out) h = ForwardDiff.hessian(out) - # current v0.3 style + # ForwardDiff v0.3 & above using DiffBase out = DiffBase.HessianResult(x) ForwardDiff.hessian!(out, f, x) @@ -86,10 +92,10 @@ derivatives by composing existing API functions. For example, here's how to reim .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 ForwardDiff.tensor(f, x) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above function tensor(f, x) n = length(x) out = ForwardDiff.jacobian(y -> ForwardDiff.hessian(f, y), x) @@ -108,26 +114,26 @@ ForwardDiff's API functions, see `our API documentation `_. .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 df = ForwardDiff.derivative(f) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above df = x -> ForwardDiff.derivative(f, x) .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 # in-place gradient function of f gf! = ForwardDiff.gradient(f, mutates = true) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above gf! = (out, x) -> ForwardDiff.gradient!(out, f, x) .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 # in-place Jacobian function of f!(y, x): jf! = ForwardDiff.jacobian(f!, mutates = true, output_length = length(y)) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above jf! = (out, y, x) -> ForwardDiff.jacobian!(out, f!, y, x) diff --git a/docs/_sources/advanced_usage.txt b/docs/_sources/advanced_usage.txt index 576cc4ee..df0c887d 100644 --- a/docs/_sources/advanced_usage.txt +++ b/docs/_sources/advanced_usage.txt @@ -9,7 +9,7 @@ Accessing Lower-Order Results Let's say you want to calculate the value, gradient, and Hessian of some function ``f`` at an input ``x``. You could execute ``f(x)``, ``ForwardDiff.gradient(f, x)`` and -``ForwardDiff.hessian(f, x)``, but that would be a **horribly redundant way to accomplish +``ForwardDiff.hessian(f, x)``, but that would be a **horribly redundant way to accomplish this task!** In the course of calculating higher-order derivatives, ForwardDiff ends up calculating all @@ -37,7 +37,7 @@ For example: .. code-block:: julia - julia> import ForwardDiff + julia> using ForwardDiff: GradientConfig, Chunk, gradient! # let's use a Rosenbrock function as our target function julia> function rosenbrock(x) @@ -58,25 +58,25 @@ For example: julia> out = similar(x); # construct GradientConfig with chunk size of 1 - julia> cfg1 = ForwardDiff.GradientConfig{1}(x); + julia> cfg1 = GradientConfig(rosenbrock, x, Chunk{1}()); # construct GradientConfig with chunk size of 4 - julia> cfg4 = ForwardDiff.GradientConfig{4}(x); + julia> cfg4 = GradientConfig(rosenbrock, x, Chunk{4}()); # construct GradientConfig with chunk size of 10 - julia> cfg10 = ForwardDiff.GradientConfig{10}(x); + julia> cfg10 = GradientConfig(rosenbrock, x, Chunk{10}()); # (input length of 10000) / (chunk size of 1) = (10000 1-element chunks) - julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg1); - 0.408305 seconds (4 allocations: 160 bytes) + julia> @time gradient!(out, rosenbrock, x, cfg1); + 0.775139 seconds (4 allocations: 160 bytes) # (input length of 10000) / (chunk size of 4) = (2500 4-element chunks) - julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg4); - 0.295764 seconds (4 allocations: 160 bytes) + julia> @time gradient!(out, rosenbrock, x, cfg4); + 0.386459 seconds (4 allocations: 160 bytes) # (input length of 10000) / (chunk size of 10) = (1000 10-element chunks) - julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg10); - 0.267396 seconds (4 allocations: 160 bytes) + julia> @time gradient!(out, rosenbrock, x, cfg10); + 0.282529 seconds (4 allocations: 160 bytes) If you do not explicity provide a chunk size, ForwardDiff will try to guess one for you based on your input vector: @@ -85,10 +85,10 @@ based on your input vector: # The GradientConfig constructor will automatically select a # chunk size in one is not explicitly provided - julia> cfg = ForwardDiff.GradientConfig(x); + julia> cfg = ForwardDiff.GradientConfig(rosenbrock, x); julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg); - 0.266920 seconds (4 allocations: 160 bytes) + 0.281853 seconds (4 allocations: 160 bytes) If your input dimension is a constant, you should explicitly select a chunk size rather than relying on ForwardDiff's heuristic. There are two reasons for this. The first is that @@ -130,8 +130,8 @@ aren't sensitive to the input and thus cause ForwardDiff to incorrectly return ` # the dual number's perturbation component is zero, so this # variable should not propagate derivative information - julia> log(ForwardDiff.Dual(0.0, 0.0)) - Dual(-Inf,NaN) # oops, this NaN should be 0.0 + julia> log(ForwardDiff.Dual{:tag}(0.0, 0.0)) + Dual{:tag}(-Inf,NaN) # oops, this NaN should be 0.0 Here, ForwardDiff computes the derivative of ``log(0.0)`` as ``NaN`` and then propagates this derivative by multiplying it by the perturbation component. Usually, ForwardDiff can @@ -153,7 +153,6 @@ In the future, we plan on allowing users and downstream library authors to dynam enable ``NaN``-safe mode via the ``AbstractConfig`` API (see `the relevant issue `_). - Hessian of a vector-valued function ----------------------------------- @@ -163,17 +162,17 @@ For example: .. code-block:: julia - julia> ForwardDiff.jacobian(x -> ForwardDiff.jacobian(sin, x), [1,2,3]) - 9×3 Array{Float64,2}: - -0.841471 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.0 - 0.0 0.0 0.0 - -0.0 -0.909297 -0.0 - -0.0 -0.0 -0.0 - 0.0 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.14112 + julia> ForwardDiff.jacobian(x -> ForwardDiff.jacobian(cumprod, x), [1,2,3]) + 9×3 Array{Int64,2}: + 0 0 0 + 0 1 0 + 0 3 2 + 0 0 0 + 1 0 0 + 3 0 1 + 0 0 0 + 0 0 0 + 2 1 0 Since this functionality is composed from ForwardDiff's existing API rather than built into it, you're free to construct a ``vector_hessian`` function which suits your needs. For @@ -190,22 +189,22 @@ expensive operation): end vector_hessian (generic function with 1 method) - julia> vector_hessian(sin, [1, 2, 3]) - 3×3×3 Array{Float64,3}: + julia> vector_hessian(cumprod, [1, 2, 3]) + 3×3×3 Array{Int64,3}: [:, :, 1] = - -0.841471 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.0 + 0 0 0 + 0 1 0 + 0 3 2 [:, :, 2] = - 0.0 0.0 0.0 - -0.0 -0.909297 -0.0 - -0.0 -0.0 -0.0 + 0 0 0 + 1 0 0 + 3 0 1 [:, :, 3] = - 0.0 0.0 0.0 - -0.0 -0.0 -0.0 - -0.0 -0.0 -0.14112 + 0 0 0 + 0 0 0 + 2 1 0 Likewise, you could write a version of ``vector_hessian`` which supports functions of the form ``f!(y, x)``, or perhaps an in-place Jacobian with ``ForwardDiff.jacobian!``. @@ -232,10 +231,10 @@ SIMD instructions (i.e. not starting Julia with ``-O3``): julia> using ForwardDiff: Dual julia> a = Dual(1., 2., 3., 4.) - Dual(1.0,2.0,3.0,4.0) + Dual{Void}(1.0,2.0,3.0,4.0) julia> b = Dual(5., 6., 7., 8.) - Dual(5.0,6.0,7.0,8.0) + Dual{Void}(5.0,6.0,7.0,8.0) julia> @code_llvm a + b diff --git a/docs/_sources/basic_api.txt b/docs/_sources/basic_api.txt index 28eb6392..96115abd 100644 --- a/docs/_sources/basic_api.txt +++ b/docs/_sources/basic_api.txt @@ -4,22 +4,26 @@ Basic ForwardDiff API Derivatives of :math:`f(x) : \mathbb{R} \to \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k}` -------------------------------------------------------------------------------------------------- -Use ``ForwardDiff.derivative`` to differentiate functions of the form ``f(::Real)::Real`` and ``f(::Real)::AbstractArray``. +Use ``ForwardDiff.derivative`` to differentiate functions of the form ``f(::Real...)::Real`` and ``f(::Real...)::AbstractArray``. .. function:: ForwardDiff.derivative!(out, f, x) - Compute :math:`f'(x)`, storing the output in ``out``. + Compute :math:`f'(x)`, storing the output in ``out``. If ``x`` is a ``Tuple``, + then ``f`` will be called as ``f(x...)`` and the derivatives with respect to + each element in `x` will be stored in the respective element of ``out`` (which + should also be a ``Tuple``). .. function:: ForwardDiff.derivative(f, x) - Compute and return :math:`f'(x)`. + Compute and return :math:`f'(x)`. If ``x`` is a ``Tuple``, ``f`` will be + called as ``f(x...)``, and a ``Tuple`` of derivatives will be returned. Gradients of :math:`f(x) : \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k} \to \mathbb{R}` ------------------------------------------------------------------------------------------------ Use ``ForwardDiff.gradient`` to differentiate functions of the form ``f(::AbstractArray)::Real``. -.. function:: ForwardDiff.gradient!(out, f, x, cfg = ForwardDiff.GradientConfig(x)) +.. function:: ForwardDiff.gradient!(out, f, x, cfg = ForwardDiff.GradientConfig(f, x)) Compute :math:`\nabla f(\vec{x})`, storing the output in ``out``. It is highly advised to preallocate ``cfg`` yourself (see the `AbstractConfig @@ -34,23 +38,23 @@ Jacobians of :math:`f(x) : \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k} Use ``ForwardDiff.jacobian`` to differentiate functions of the form ``f(::AbstractArray)::AbstractArray``. -.. function:: ForwardDiff.jacobian!(out, f, x, cfg = ForwardDiff.JacobianConfig(x)) +.. function:: ForwardDiff.jacobian!(out, f, x, cfg = ForwardDiff.JacobianConfig(f, x)) Compute :math:`\mathbf{J}(f)(\vec{x})`, storing the output in ``out``. It is highly advised to preallocate ``cfg`` yourself (see the `AbstractConfig `_ section below). -.. function:: ForwardDiff.jacobian!(out, f!, y, x, cfg = ForwardDiff.JacobianConfig(y, x)) +.. function:: ForwardDiff.jacobian!(out, f!, y, x, cfg = ForwardDiff.JacobianConfig(f!, y, x)) Compute :math:`\mathbf{J}(f)(\vec{x})`, where :math:`f(\vec{x})` can be called as ``f!(y, x)`` such that the output of :math:`f(\vec{x})` is stored in ``y``. The output matrix is stored in ``out``. -.. function:: ForwardDiff.jacobian(f, x, cfg = ForwardDiff.JacobianConfig(x)) +.. function:: ForwardDiff.jacobian(f, x, cfg = ForwardDiff.JacobianConfig(f, x)) Compute and return :math:`\mathbf{J}(f)(\vec{x})`. -.. function:: ForwardDiff.jacobian(f!, y, x, cfg = ForwardDiff.JacobianConfig(y, x)) +.. function:: ForwardDiff.jacobian(f!, y, x, cfg = ForwardDiff.JacobianConfig(f!, y, x)) Compute and return :math:`\mathbf{J}(f)(\vec{x})`, where :math:`f(\vec{x})` can be called as ``f!(y, x)`` such that the output of :math:`f(\vec{x})` is stored in ``y``. @@ -60,13 +64,13 @@ Hessians of :math:`f(x) : \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k} Use ``ForwardDiff.hessian`` to perform second-order differentiation on functions of the form ``f(::AbstractArray)::Real``. -.. function:: ForwardDiff.hessian!(out, f, x, cfg = ForwardDiff.HessianConfig(x)) +.. function:: ForwardDiff.hessian!(out, f, x, cfg = ForwardDiff.HessianConfig(f, x)) Compute :math:`\mathbf{H}(f)(\vec{x})`, storing the output in ``out``. It is highly advised to preallocate ``cfg`` yourself (see the `AbstractConfig `_ section below). -.. function:: ForwardDiff.hessian(f, x, cfg = ForwardDiff.HessianConfig(x)) +.. function:: ForwardDiff.hessian(f, x, cfg = ForwardDiff.HessianConfig(f, x)) Compute and return :math:`\mathbf{H}(f)(\vec{x})`. @@ -77,66 +81,63 @@ For the sake of convenience and performance, all "extra" information used by For API methods is bundled up in the ``ForwardDiff.AbstractConfig`` family of types. Theses types allow the user to easily feed several different parameters to ForwardDiff's API methods, such as `chunk size `_, work buffers, -multithreading configurations, and perturbation seed configurations. +and perturbation seed configurations. ForwardDiff's basic API methods will allocate these types automatically by default, but you can drastically reduce memory usage if you preallocate them yourself. -Note that for all constructors below, the chunk size ``N`` may be explictly provided as a -type parameter, or omitted, in which case ForwardDiff will automatically select a chunk size -for you. However, it is highly recomended to `specify the chunk size manually when possible +Note that for all constructors below, the chunk size ``N`` may be explictly provided, +or omitted, in which case ForwardDiff will automatically select a chunk size for you. +However, it is highly recomended to `specify the chunk size manually when possible `_. -.. function:: ForwardDiff.GradientConfig{N}(x) +Note also that configurations constructed for a specific function ``f`` cannot +be reused to differentiate other functions (though can be reused to differentiate +``f`` at different values). To construct a configuration which can be reused to +differentiate any function, you can pass ``nothing`` as the function argument. +While this is more flexible, this decreases ForwardDiff's ability to catch +and prevent `perturbation confusion`_. - Construct a ``GradientConfig`` instance based on the type and shape of the input vector - ``x``. The returned ``GradientConfig`` instance contains all the work buffers required - by ForwardDiff's gradient/Jacobian methods. If taking the Jacobian of a target function - with the form ``f!(y, x)``, use the constructor ``ForwardDiff.GradientConfig{N}(y, x)`` - instead. +.. function:: ForwardDiff.GradientConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) + + Construct a ``GradientConfig`` instance based on the type of ``f`` and + type/shape of the input vector ``x``. The returned ``GradientConfig`` + instance contains all the work buffers required by ForwardDiff's gradient + methods. This constructor does not store/modify ``x``. -.. function:: ForwardDiff.JacobianConfig{N}(x) +.. function:: ForwardDiff.JacobianConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Exactly like ``ForwardDiff.GradientConfig{N}(x)``, but returns a `JacobianConfig` - instead. + Exactly like the ``GradientConfig`` constructor, but returns a ``JacobianConfig`` instead. -.. function:: ForwardDiff.JacobianConfig{N}(y, x) +.. function:: ForwardDiff.JacobianConfig(f!, y, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Construct a ``JacobianConfig`` instance based on the type and shape of the output vector - ``y`` and the input vector ``x``. The returned ``JacobianConfig`` instance contains all - the work buffers required by ``ForwardDiff.jacobian``/``ForwardDiff.jacobian!`` with a - target function of the form ``f!(y, x)``. + Construct a ``JacobianConfig`` instance based on the type of ``f!``, and the + types/shapes of the output vector ``y`` and the input vector ``x``. The + returned ``JacobianConfig`` instance contains all the work buffers required + by ``ForwardDiff.jacobian``/``ForwardDiff.jacobian!`` when the target + function takes the form ``f!(y, x)``. This constructor does not store/modify ``y`` or ``x``. -.. function:: ForwardDiff.HessianConfig{N}(x) +.. function:: ForwardDiff.HessianConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Construct a ``HessianConfig`` instance based on the type and shape of the input vector - ``x``. The returned ``HessianConfig`` instance contains all the work buffers required - by ForwardDiff's Hessian methods. If using - ``ForwardDiff.hessian!(out::DiffBase.DiffResult, args...)``, use the constructor - ``ForwardDiff.HessianConfig{N}(out, x)`` instead. + Construct a ``HessianConfig`` instance based on the type of ``f`` and + type/shape of the input vector ``x``. The returned ``HessianConfig`` instance contains + all the work buffers required by ForwardDiff's Hessian methods. If using + ``ForwardDiff.hessian!(out::DiffBase.DiffResult, f, x)``, use the constructor + ``ForwardDiff.HessianConfig(f, out, x, chunk)`` instead. This constructor does not store/modify ``x``. -.. function:: ForwardDiff.HessianConfig{N}(out::DiffBase.DiffResult, x) +.. function:: ForwardDiff.HessianConfig(f, out::DiffBase.DiffResult, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) - Construct an ``HessianConfig`` instance based on the type and shape of the storage in - ``out`` and the input vector ``x``. The returned ``HessianConfig`` instance contains - all the work buffers required by ``ForwardDiff.hessian!(out::DiffBase.DiffResult, - args...)``. + Construct an ``HessianConfig`` instance based on the type of ``f``, types/storage + in ``out``, and type/shape of the input vector ``x``. The returned ``HessianConfig`` + instance contains all the work buffers required by + ``ForwardDiff.hessian!(out::DiffBase.DiffResult, args...)``. This constructor does not store/modify ``out`` or ``x``. -.. function:: ForwardDiff.MultithreadConfig(cfg::AbstractConfig) - - Wrap the given ``cfg`` in a ``MultithreadConfig`` instance, which can then be passed to - gradient or Hessian methods in order to enable experimental multithreading. Jacobian - methods do not yet support multithreading. - - Note that multithreaded ForwardDiff API methods will attempt to use all available - threads. In the future, once Julia exposes more fine-grained threading primitives, - a ``MultithreadConfig`` constructor may be added which takes in a user-provided subset - of thread IDs instead of using all available threads. +.. _`perturbation confusion`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/83 diff --git a/docs/_sources/contributing.txt b/docs/_sources/contributing.txt index cb669228..7de30bdc 100644 --- a/docs/_sources/contributing.txt +++ b/docs/_sources/contributing.txt @@ -40,9 +40,7 @@ To see a list of functions to pick from, look at ``ForwardDiff.AUTO_DEFINED_UNAR ⋮ Some of these functions may have already been manually optimized. To see what functions have -already been done, go to ``src/dual.jl``, scroll down to the ``Special Cases`` section, and -look at the functions under ``Manually Optimized`` (further optimizations to these functions -are always welcome, if you can come up with something clever). +already been done, go to ``src/dual.jl`` and scroll down to the ``Special Cases`` section. The functions in ``ForwardDiff.AUTO_DEFINED_UNARY_FUNCS`` are automatically tested as part of ForwardDiff's test suite, so you don't need to write tests yourself. You can test your diff --git a/docs/_sources/how_it_works.txt b/docs/_sources/how_it_works.txt index 20a96e49..dd8114cb 100644 --- a/docs/_sources/how_it_works.txt +++ b/docs/_sources/how_it_works.txt @@ -9,25 +9,26 @@ Julia. There are two key components of this implementation: the ``Dual`` type, a Dual Number Implementation -------------------------- -Partial derivatives are stored in the ``Partials{N,T}`` type: +Partial derivatives are stored in the ``Partials{N,V}`` type: .. code-block:: julia - immutable Partials{N,T} - values::NTuple{N,T} + struct Partials{N,V} <: AbstractVector{V} + values::NTuple{N,V} end -Overtop of this container type, ForwardDiff implements the ``Dual{N,T}`` type: +Overtop of this container type, ForwardDiff implements the ``Dual{T,V,N}`` type: .. code-block:: julia - immutable Dual{N,T<:Real} <: Real - value::T - partials::Partials{N,T} + struct Dual{T,V<:Real,N} <: Real + value::V + partials::Partials{N,V} end -This type represents an ``N``-dimensional `dual number`_ with the following mathematical -behavior: +This type represents an ``N``-dimensional `dual number`_ coupled with a tag +parameter `T` in order to prevent `perturbation confusion`_. This dual number +type is implemented to have the following mathematical behavior: .. math:: @@ -44,22 +45,23 @@ can be overloaded on ``Dual`` like so: .. code-block:: julia - Base.sin(d::Dual) = Dual(sin(value(d)), cos(value(d)) * partials(d)) + Base.sin(d::Dual{T}) where {T} = Dual{T}(sin(value(d)), cos(value(d)) * partials(d)) If we assume that a general function ``f`` is composed of entirely of these elementary functions, then the chain rule enables our derivatives to compose as well. Thus, by overloading a plethora of elementary functions, we can differentiate generic functions composed of them by passing in a ``Dual`` number and looking at the output. -We won't dicuss higher-order differentiation in detail, but the reader is encouraged to +We won't discuss higher-order differentiation in detail, but the reader is encouraged to learn about `hyper-dual numbers`_, which extend dual numbers to higher orders by introducing extra :math:`\epsilon` terms that can cross-multiply. ForwardDiff's ``Dual`` number implementation naturally supports hyper-dual numbers without additional code by allowing instances of the ``Dual`` type to nest within each other. For example, a second-order -hyper-dual number has the type ``Dual{N,Dual{N,T}}``, a third-order hyper-dual number has -the type ``Dual{N,Dual{N,Dual{N,T}}}``, and so on. +hyper-dual number has the type ``Dual{T,Dual{S,V,M},N}``, a third-order hyper-dual number has +the type ``Dual{T,Dual{S,Dual{R,V,K},M},N}``, and so on. .. _`dual number`: https://en.wikipedia.org/wiki/Dual_number +.. _`perturbation confusion`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/83 .. _`hyper-dual numbers`: https://adl.stanford.edu/hyperdual/Fike_AIAA-2011-886.pdf ForwardDiff's API diff --git a/docs/_sources/install.txt b/docs/_sources/install.txt index bb7668d6..4f3573b6 100644 --- a/docs/_sources/install.txt +++ b/docs/_sources/install.txt @@ -7,4 +7,4 @@ To install ForwardDiff, simply use Julia's package manager: julia> Pkg.add("ForwardDiff") -The current version of ForwardDiff supports Julia v0.4 and v0.5. +The current version of ForwardDiff supports Julia v0.6. diff --git a/docs/_sources/limitations.txt b/docs/_sources/limitations.txt index 9862d12b..65ecb75a 100644 --- a/docs/_sources/limitations.txt +++ b/docs/_sources/limitations.txt @@ -12,10 +12,7 @@ function being differentiated): - **The target function must be written generically enough to accept numbers of type ``T<:Real`` as input (or arrays of these numbers).** The function doesn't require a specific type signature, as long as the type signature is generic enough to avoid breaking this rule. This also means that any storage assigned used within the function must be generic as well (see `this comment`_ for an example). -- **Nested differentiation of closures is dangerous.** Differentiating closures is safe, and nested differentation is safe, but you might be vulnerable to a subtle bug if you try to do both. See `the relevant issue`_ for details. - - **The types of array inputs must be subtypes of** ``AbstractArray`` **.** Non-``AbstractArray`` array-like types are not officially supported. .. _`this comment`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/136#issuecomment-237941790 -.. _`the relevant issue`: https://github.com/JuliaDiff/ForwardDiff.jl/issues/83 .. _`this file`: https://github.com/JuliaDiff/ForwardDiff.jl/blob/master/src/cache.jl diff --git a/docs/_sources/upgrade.txt b/docs/_sources/upgrade.txt index 5fc2ef82..a0afb6af 100644 --- a/docs/_sources/upgrade.txt +++ b/docs/_sources/upgrade.txt @@ -14,11 +14,11 @@ functions to reference them: .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 using ForwardDiff hessian(f, x) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above using ForwardDiff ForwardDiff.hessian(f, x) @@ -27,26 +27,32 @@ Setting Chunk Size .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 ForwardDiff.gradient(f, x; chunk_size = 10) - # old v0.2 style + # ForwardDiff v0.2 ForwardDiff.gradient(f, x, Chunk{10}()) - # current v0.3 style + # ForwardDiff v0.3 & v0.4 ForwardDiff.gradient(f, x, ForwardDiff.GradientConfig{10}(x)) + # ForwardDiff v0.5 & above + ForwardDiff.gradient(f, x, ForwardDiff.GradientConfig(f, x ForwardDiff.Chunk{N}())) + Enabling Multithreading ----------------------- .. code-block:: julia - # old v0.1/v0.2 style + # ForwardDiff v0.1 & v0.2 ForwardDiff.gradient(f, x; multithread = true) - # current v0.3 style + # ForwardDiff v0.3 & v0.4 ForwardDiff.gradient(f, x, ForwardDiff.MultithreadConfig(ForwardDiff.GradientConfig(x))) + # ForwardDiff v0.5 & above + error("ForwardDiff no longer supports internal multithreading.") + Retrieving Lower-Order Results ------------------------------ @@ -55,20 +61,20 @@ For more detail, see our documentation on `retrieving lower-order results .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 answer, results = ForwardDiff.hessian(f, x, AllResults) v = ForwardDiff.value(results) g = ForwardDiff.gradient(results) h = ForwardDiff.hessian(results) # == answer - # old v0.2 style + # ForwardDiff v0.2 out = HessianResult(x) ForwardDiff.hessian!(out, f, x) v = ForwardDiff.value(out) g = ForwardDiff.gradient(out) h = ForwardDiff.hessian(out) - # current v0.3 style + # ForwardDiff v0.3 & above using DiffBase out = DiffBase.HessianResult(x) ForwardDiff.hessian!(out, f, x) @@ -86,10 +92,10 @@ derivatives by composing existing API functions. For example, here's how to reim .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 ForwardDiff.tensor(f, x) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above function tensor(f, x) n = length(x) out = ForwardDiff.jacobian(y -> ForwardDiff.hessian(f, y), x) @@ -108,26 +114,26 @@ ForwardDiff's API functions, see `our API documentation `_. .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 df = ForwardDiff.derivative(f) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above df = x -> ForwardDiff.derivative(f, x) .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 # in-place gradient function of f gf! = ForwardDiff.gradient(f, mutates = true) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above gf! = (out, x) -> ForwardDiff.gradient!(out, f, x) .. code-block:: julia - # old v0.1 style + # ForwardDiff v0.1 # in-place Jacobian function of f!(y, x): jf! = ForwardDiff.jacobian(f!, mutates = true, output_length = length(y)) - # current v0.3 style (since v0.2) + # ForwardDiff v0.2 & above jf! = (out, y, x) -> ForwardDiff.jacobian!(out, f!, y, x) diff --git a/docs/advanced_usage.html b/docs/advanced_usage.html index 47bc8814..0d1e7da1 100644 --- a/docs/advanced_usage.html +++ b/docs/advanced_usage.html @@ -8,7 +8,7 @@ - Advanced Usage Guide — ForwardDiff.jl 0.2.3 documentation + Advanced Usage Guide — ForwardDiff.jl 0.5.0 documentation @@ -30,7 +30,7 @@ - + @@ -60,7 +60,7 @@
- 0.2 + 0.5
@@ -152,7 +152,7 @@

Advanced Usage GuideAccessing Lower-Order Results

Let’s say you want to calculate the value, gradient, and Hessian of some function f at an input x. You could execute f(x), ForwardDiff.gradient(f, x) and -ForwardDiff.hessian(f, x), but that would be a horribly redundant way to accomplish +ForwardDiff.hessian(f, x), but that would be a horribly redundant way to accomplish this task!

In the course of calculating higher-order derivatives, ForwardDiff ends up calculating all the lower-order derivatives and primal value f(x). To retrieve these results in one fell @@ -172,7 +172,7 @@

Configuring Chunk Size

For example:

-
julia> import ForwardDiff
+
julia> using ForwardDiff: GradientConfig, Chunk, gradient!
 
 # let's use a Rosenbrock function as our target function
 julia> function rosenbrock(x)
@@ -193,35 +193,35 @@ 

Configuring Chunk Sizejulia> out = similar(x); # construct GradientConfig with chunk size of 1 -julia> cfg1 = ForwardDiff.GradientConfig{1}(x); +julia> cfg1 = GradientConfig(rosenbrock, x, Chunk{1}()); # construct GradientConfig with chunk size of 4 -julia> cfg4 = ForwardDiff.GradientConfig{4}(x); +julia> cfg4 = GradientConfig(rosenbrock, x, Chunk{4}()); # construct GradientConfig with chunk size of 10 -julia> cfg10 = ForwardDiff.GradientConfig{10}(x); +julia> cfg10 = GradientConfig(rosenbrock, x, Chunk{10}()); # (input length of 10000) / (chunk size of 1) = (10000 1-element chunks) -julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg1); - 0.408305 seconds (4 allocations: 160 bytes) +julia> @time gradient!(out, rosenbrock, x, cfg1); + 0.775139 seconds (4 allocations: 160 bytes) # (input length of 10000) / (chunk size of 4) = (2500 4-element chunks) -julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg4); - 0.295764 seconds (4 allocations: 160 bytes) +julia> @time gradient!(out, rosenbrock, x, cfg4); + 0.386459 seconds (4 allocations: 160 bytes) # (input length of 10000) / (chunk size of 10) = (1000 10-element chunks) -julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg10); - 0.267396 seconds (4 allocations: 160 bytes) +julia> @time gradient!(out, rosenbrock, x, cfg10); + 0.282529 seconds (4 allocations: 160 bytes)

If you do not explicity provide a chunk size, ForwardDiff will try to guess one for you based on your input vector:

# The GradientConfig constructor will automatically select a
 # chunk size in one is not explicitly provided
-julia> cfg = ForwardDiff.GradientConfig(x);
+julia> cfg = ForwardDiff.GradientConfig(rosenbrock, x);
 
 julia> @time ForwardDiff.gradient!(out, rosenbrock, x, cfg);
-0.266920 seconds (4 allocations: 160 bytes)
+  0.281853 seconds (4 allocations: 160 bytes)
 

If your input dimension is a constant, you should explicitly select a chunk size rather than @@ -256,8 +256,8 @@

Fixing issues with NaN/Inf return valuesInf derivatives. For example:

# the dual number's perturbation component is zero, so this
 # variable should not propagate derivative information
-julia> log(ForwardDiff.Dual(0.0, 0.0))
-Dual(-Inf,NaN) # oops, this NaN should be 0.0
+julia> log(ForwardDiff.Dual{:tag}(0.0, 0.0))
+Dual{:tag}(-Inf,NaN) # oops, this NaN should be 0.0
 

Here, ForwardDiff computes the derivative of log(0.0) as NaN and then propagates @@ -281,17 +281,17 @@

Hessian of a vector-valued functionForwardDiff.jacobian to accomplish this. For example:

-

Likewise, you could write a version of vector_hessian which supports functions of the @@ -340,10 +340,10 @@

SIMD Vectorization
julia> using ForwardDiff: Dual
 
 julia> a = Dual(1., 2., 3., 4.)
-Dual(1.0,2.0,3.0,4.0)
+Dual{Void}(1.0,2.0,3.0,4.0)
 
 julia> b = Dual(5., 6., 7., 8.)
-Dual(5.0,6.0,7.0,8.0)
+Dual{Void}(5.0,6.0,7.0,8.0)
 
 julia> @code_llvm a + b
 
@@ -445,7 +445,7 @@ 

SIMD Vectorization var DOCUMENTATION_OPTIONS = { URL_ROOT:'./', - VERSION:'0.2.3', + VERSION:'0.5.0', COLLAPSE_INDEX:false, FILE_SUFFIX:'.html', HAS_SOURCE: true diff --git a/docs/basic_api.html b/docs/basic_api.html index 882019e8..862d63fb 100644 --- a/docs/basic_api.html +++ b/docs/basic_api.html @@ -8,7 +8,7 @@ - Basic ForwardDiff API — ForwardDiff.jl 0.2.3 documentation + Basic ForwardDiff API — ForwardDiff.jl 0.5.0 documentation @@ -30,7 +30,7 @@ - + @@ -60,7 +60,7 @@
- 0.2 + 0.5
@@ -148,17 +148,21 @@

Basic ForwardDiff API

Derivatives of \(f(x) : \mathbb{R} \to \mathbb{R}^{n_1} \times \dots \times \mathbb{R}^{n_k}\)

-

Use ForwardDiff.derivative to differentiate functions of the form f(::Real)::Real and f(::Real)::AbstractArray.

+

Use ForwardDiff.derivative to differentiate functions of the form f(::Real...)::Real and f(::Real...)::AbstractArray.

ForwardDiff.derivative!(out, f, x)
-

Compute \(f'(x)\), storing the output in out.

+

Compute \(f'(x)\), storing the output in out. If x is a Tuple, +then f will be called as f(x...) and the derivatives with respect to +each element in x will be stored in the respective element of out (which +should also be a Tuple).

ForwardDiff.derivative(f, x)
-

Compute and return \(f'(x)\).

+

Compute and return \(f'(x)\). If x is a Tuple, f will be +called as f(x...), and a Tuple of derivatives will be returned.

@@ -167,7 +171,7 @@

Gradients of \(f(x) : \mathbb{R}^{n_1} \times \dots \time

Use ForwardDiff.gradient to differentiate functions of the form f(::AbstractArray)::Real.

-ForwardDiff.gradient!(out, f, x, cfg = ForwardDiff.GradientConfig(x))
+ForwardDiff.gradient!(out, f, x, cfg = ForwardDiff.GradientConfig(f, x))

Compute \(\nabla f(\vec{x})\), storing the output in out. It is highly advised to preallocate cfg yourself (see the AbstractConfig section below).

@@ -184,14 +188,14 @@

Jacobians of \(f(x) : \mathbb{R}^{n_1} \times \dots \time

Use ForwardDiff.jacobian to differentiate functions of the form f(::AbstractArray)::AbstractArray.

-ForwardDiff.jacobian!(out, f, x, cfg = ForwardDiff.JacobianConfig(x))
+ForwardDiff.jacobian!(out, f, x, cfg = ForwardDiff.JacobianConfig(f, x))

Compute \(\mathbf{J}(f)(\vec{x})\), storing the output in out. It is highly advised to preallocate cfg yourself (see the AbstractConfig section below).

-ForwardDiff.jacobian!(out, f!, y, x, cfg = ForwardDiff.JacobianConfig(y, x))
+ForwardDiff.jacobian!(out, f!, y, x, cfg = ForwardDiff.JacobianConfig(f!, y, x))

Compute \(\mathbf{J}(f)(\vec{x})\), where \(f(\vec{x})\) can be called as f!(y, x) such that the output of \(f(\vec{x})\) is stored in y. The output matrix is stored in out.

@@ -199,13 +203,13 @@

Jacobians of \(f(x) : \mathbb{R}^{n_1} \times \dots \time
-ForwardDiff.jacobian(f, x, cfg = ForwardDiff.JacobianConfig(x))
+ForwardDiff.jacobian(f, x, cfg = ForwardDiff.JacobianConfig(f, x))

Compute and return \(\mathbf{J}(f)(\vec{x})\).

-ForwardDiff.jacobian(f!, y, x, cfg = ForwardDiff.JacobianConfig(y, x))
+ForwardDiff.jacobian(f!, y, x, cfg = ForwardDiff.JacobianConfig(f!, y, x))

Compute and return \(\mathbf{J}(f)(\vec{x})\), where \(f(\vec{x})\) can be called as f!(y, x) such that the output of \(f(\vec{x})\) is stored in y.

@@ -216,14 +220,14 @@

Hessians of \(f(x) : \mathbb{R}^{n_1} \times \dots \times

Use ForwardDiff.hessian to perform second-order differentiation on functions of the form f(::AbstractArray)::Real.

-ForwardDiff.hessian!(out, f, x, cfg = ForwardDiff.HessianConfig(x))
+ForwardDiff.hessian!(out, f, x, cfg = ForwardDiff.HessianConfig(f, x))

Compute \(\mathbf{H}(f)(\vec{x})\), storing the output in out. It is highly advised to preallocate cfg yourself (see the AbstractConfig section below).

-ForwardDiff.hessian(f, x, cfg = ForwardDiff.HessianConfig(x))
+ForwardDiff.hessian(f, x, cfg = ForwardDiff.HessianConfig(f, x))

Compute and return \(\mathbf{H}(f)(\vec{x})\).

@@ -234,73 +238,66 @@

The AbstractConfigForwardDiff.AbstractConfig family of types. Theses types allow the user to easily feed several different parameters to ForwardDiff’s API methods, such as chunk size, work buffers, -multithreading configurations, and perturbation seed configurations.

+and perturbation seed configurations.

ForwardDiff’s basic API methods will allocate these types automatically by default, but you can drastically reduce memory usage if you preallocate them yourself.

-

Note that for all constructors below, the chunk size N may be explictly provided as a -type parameter, or omitted, in which case ForwardDiff will automatically select a chunk size -for you. However, it is highly recomended to specify the chunk size manually when possible.

+

Note that for all constructors below, the chunk size N may be explictly provided, +or omitted, in which case ForwardDiff will automatically select a chunk size for you. +However, it is highly recomended to specify the chunk size manually when possible.

+

Note also that configurations constructed for a specific function f cannot +be reused to differentiate other functions (though can be reused to differentiate +f at different values). To construct a configuration which can be reused to +differentiate any function, you can pass nothing as the function argument. +While this is more flexible, this decreases ForwardDiff’s ability to catch +and prevent perturbation confusion.

-
-ForwardDiff.GradientConfig{N}(x)
-

Construct a GradientConfig instance based on the type and shape of the input vector -x. The returned GradientConfig instance contains all the work buffers required -by ForwardDiff’s gradient/Jacobian methods. If taking the Jacobian of a target function -with the form f!(y, x), use the constructor ForwardDiff.GradientConfig{N}(y, x) -instead.

+
+ForwardDiff.GradientConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x))
+

Construct a GradientConfig instance based on the type of f and +type/shape of the input vector x. The returned GradientConfig +instance contains all the work buffers required by ForwardDiff’s gradient +methods.

This constructor does not store/modify x.

-
-ForwardDiff.JacobianConfig{N}(x)
-

Exactly like ForwardDiff.GradientConfig{N}(x), but returns a JacobianConfig -instead.

+
+ForwardDiff.JacobianConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x))
+

Exactly like the GradientConfig constructor, but returns a JacobianConfig instead.

-ForwardDiff.JacobianConfig{N}(y, x)
-

Construct a JacobianConfig instance based on the type and shape of the output vector -y and the input vector x. The returned JacobianConfig instance contains all -the work buffers required by ForwardDiff.jacobian/ForwardDiff.jacobian! with a -target function of the form f!(y, x).

+ForwardDiff.JacobianConfig(f!, y, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) +

Construct a JacobianConfig instance based on the type of f!, and the +types/shapes of the output vector y and the input vector x. The +returned JacobianConfig instance contains all the work buffers required +by ForwardDiff.jacobian/ForwardDiff.jacobian! when the target +function takes the form f!(y, x).

This constructor does not store/modify y or x.

-
-ForwardDiff.HessianConfig{N}(x)
-

Construct a HessianConfig instance based on the type and shape of the input vector -x. The returned HessianConfig instance contains all the work buffers required -by ForwardDiff’s Hessian methods. If using -ForwardDiff.hessian!(out::DiffBase.DiffResult, args...), use the constructor -ForwardDiff.HessianConfig{N}(out, x) instead.

+
+ForwardDiff.HessianConfig(f, x, chunk::ForwardDiff.Chunk{N} = Chunk(x))
+

Construct a HessianConfig instance based on the type of f and +type/shape of the input vector x. The returned HessianConfig instance contains +all the work buffers required by ForwardDiff’s Hessian methods. If using +ForwardDiff.hessian!(out::DiffBase.DiffResult, f, x), use the constructor +ForwardDiff.HessianConfig(f, out, x, chunk) instead.

This constructor does not store/modify x.

-ForwardDiff.HessianConfig{N}(out::DiffBase.DiffResult, x)
-

Construct an HessianConfig instance based on the type and shape of the storage in -out and the input vector x. The returned HessianConfig instance contains -all the work buffers required by ForwardDiff.hessian!(out::DiffBase.DiffResult, -args...).

+ForwardDiff.HessianConfig(f, out::DiffBase.DiffResult, x, chunk::ForwardDiff.Chunk{N} = Chunk(x)) +

Construct an HessianConfig instance based on the type of f, types/storage +in out, and type/shape of the input vector x. The returned HessianConfig +instance contains all the work buffers required by +ForwardDiff.hessian!(out::DiffBase.DiffResult, args...).

This constructor does not store/modify out or x.

-
-
-ForwardDiff.MultithreadConfig(cfg::AbstractConfig)
-

Wrap the given cfg in a MultithreadConfig instance, which can then be passed to -gradient or Hessian methods in order to enable experimental multithreading. Jacobian -methods do not yet support multithreading.

-

Note that multithreaded ForwardDiff API methods will attempt to use all available -threads. In the future, once Julia exposes more fine-grained threading primitives, -a MultithreadConfig constructor may be added which takes in a user-provided subset -of thread IDs instead of using all available threads.

-
-

@@ -345,7 +342,7 @@

The AbstractConfig var DOCUMENTATION_OPTIONS = { URL_ROOT:'./', - VERSION:'0.2.3', + VERSION:'0.5.0', COLLAPSE_INDEX:false, FILE_SUFFIX:'.html', HAS_SOURCE: true diff --git a/docs/contributing.html b/docs/contributing.html index a2102a06..5a1973b7 100644 --- a/docs/contributing.html +++ b/docs/contributing.html @@ -8,7 +8,7 @@ - How to Contribute — ForwardDiff.jl 0.2.3 documentation + How to Contribute — ForwardDiff.jl 0.5.0 documentation @@ -30,7 +30,7 @@ - + @@ -59,7 +59,7 @@
- 0.2 + 0.5
@@ -181,9 +181,7 @@

Manually Optimizing Unary Functionssrc/dual.jl, scroll down to the Special Cases section, and -look at the functions under Manually Optimized (further optimizations to these functions -are always welcome, if you can come up with something clever).

+already been done, go to src/dual.jl and scroll down to the Special Cases section.

The functions in ForwardDiff.AUTO_DEFINED_UNARY_FUNCS are automatically tested as part of ForwardDiff’s test suite, so you don’t need to write tests yourself. You can test your changes by running Pkg.test("ForwardDiff").

@@ -254,7 +252,7 @@

Manually Adding Functions to ForwardDiff var DOCUMENTATION_OPTIONS = { URL_ROOT:'./', - VERSION:'0.2.3', + VERSION:'0.5.0', COLLAPSE_INDEX:false, FILE_SUFFIX:'.html', HAS_SOURCE: true diff --git a/docs/genindex.html b/docs/genindex.html index ee28917c..28e76d10 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -9,7 +9,7 @@ - Index — ForwardDiff.jl 0.2.3 documentation + Index — ForwardDiff.jl 0.5.0 documentation @@ -31,7 +31,7 @@ - + @@ -59,7 +59,7 @@
- 0.2 + 0.5
@@ -153,17 +153,25 @@

F

+
ForwardDiff.GradientConfig() (built-in function) +
+ +
ForwardDiff.hessian() (built-in function)
+
ForwardDiff.HessianConfig() (built-in function), [1] +
+ +
ForwardDiff.jacobian() (built-in function), [1]
-
ForwardDiff.MultithreadConfig() (built-in function) +
ForwardDiff.JacobianConfig() (built-in function), [1]
@@ -202,7 +210,7 @@

F

@@ -58,7 +58,7 @@
- 0.2 + 0.5
@@ -176,7 +176,7 @@