dual
Resources & Distribution
Source Code
Package Registries
dual
Forward-mode automatic differentiation via dual numbers for C++20.
Overview
Dual numbers are a simple yet powerful technique for computing exact derivatives. The key insight: if we extend our number system with an element epsilon where epsilon^2 = 0, then evaluating f(x + epsilon) yields f(x) + epsilon * f'(x). The derivative emerges automatically from the algebra.
This library provides:
dual<T>- Dual numbers for first derivativesdual2<T>- Nested duals for second derivativesjet<T, N>- Taylor jets for arbitrary-order derivatives- Numerical differentiation - Finite difference schemes for comparison/verification
Quick Start
#include <dual/dual.hpp>
#include <iostream>
int main() {
using namespace dual;
// Create a dual variable at x = 2
auto x = dual<double>::variable(2.0);
// Compute f(x) = x^3 - 3x + 1
auto f = x*x*x - 3.0*x + 1.0;
std::cout << "f(2) = " << f.value() << "\n"; // 3.0
std::cout << "f'(2) = " << f.derivative() << "\n"; // 9.0
}
Installation
Header-only
Copy the include/dual directory to your project and add it to your include path.
CMake
add_subdirectory(dual)
target_link_libraries(your_target PRIVATE dual::dual)
System-wide
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build
cmake --install build
Building and Testing
cmake -B build
cmake --build build
ctest --test-dir build --output-on-failure
API Reference
dual
The core dual number type.
// Create a variable for differentiation
auto x = dual<double>::variable(3.0); // x = 3, dx = 1
// Create a constant
auto c = dual<double>::constant(2.0); // c = 2, dc = 0
// Access values
double val = x.value(); // 3.0
double deriv = x.derivative(); // 1.0
// Arithmetic operators: +, -, *, /
auto y = sin(x*x) + exp(-x);
// Convenience function
auto [value, deriv] = differentiate([](auto x) { return x*x; }, 3.0);
Mathematical Functions
All standard math functions are supported with correct derivative propagation:
- Basic:
sqrt,cbrt,abs - Exponential:
exp,exp2,expm1,log,log2,log10,log1p - Trigonometric:
sin,cos,tan,asin,acos,atan,atan2 - Hyperbolic:
sinh,cosh,tanh,asinh,acosh,atanh - Power:
pow,hypot - Special:
erf,erfc
Higher-Order Derivatives
Second derivatives with dual2:
auto result = differentiate2([](auto x) { return sin(x); }, 1.0);
// result.value = sin(1)
// result.first = cos(1)
// result.second = -sin(1)
Arbitrary order with jets:
// Compute f, f', f'', f''', f'''' at x = 1
auto derivs = derivatives<4>([](auto x) { return exp(x); }, 1.0);
// All derivatives of e^x at x=1 equal e
Numerical Differentiation
For verification or black-box functions:
using namespace dual::numerical;
// Various finite difference schemes
auto fd = forward_difference(f, x); // O(h)
auto cd = central_difference(f, x); // O(h^2)
auto fp = five_point_stencil(f, x); // O(h^4)
// Gradient of multivariate function
auto grad = gradient(f, {x, y, z});
// Jacobian and Hessian
auto jac = jacobian(f, x);
auto hess = hessian(f, x);
// Compare automatic vs numerical
auto cmp = compare_derivatives(f, x);
assert(cmp.agrees());
Forward vs Reverse Mode
This library implements forward mode AD:
- Pros: Simple, no memory overhead, exact derivatives
- Cons: Cost is O(n) for n input variables
For functions with many inputs and few outputs (like neural network loss functions), reverse mode (backpropagation) is more efficient. See gradator for a reverse-mode implementation.
| Use Case | Best Mode |
|---|---|
| f: R -> R^n (one input, many outputs) | Forward |
| f: R^n -> R (many inputs, one output) | Reverse |
| Jacobian-vector products | Forward |
| Vector-Jacobian products | Reverse |
Requirements
- C++20 compiler with concepts support
- CMake 3.20+ (for building)
- Google Test (optional, for testing)
License
MIT License - see LICENSE file for details.