cppduals  0.10.0
Dual numbers for C++
cppduals

Overview

cppduals is a standalone, dependency-free, header-only C++17 template library for dual number arithmetic and forward-mode automatic differentiation. It requires only a standard-conforming C++ compiler — no external dependencies.

A dual number has the form \( a + b\epsilon \) where \( \epsilon \ne 0 \) and \( \epsilon^2 = 0 \). Evaluating any differentiable function \( f \) at a dual argument \( x + \epsilon \) yields \( f(x) + f'(x)\epsilon \) — the exact derivative, with no finite-difference approximation.

Features

  • Dependency-free — only standard library headers; just copy the duals/ directory into your project.
  • Eigen integration — optional #include <duals/dual_eigen> for SIMD-vectorized matrix operations with dual-valued elements.
  • Recursive nesting — dual<dual<T>> gives second derivatives; nest further for higher orders.
  • Complex composition — std::complex<dual<T>> differentiates complex-valued functions.
  • Full math library — overloads for all standard transcendental, hyperbolic, and special functions (exp, log, pow, sin, cos, erf, tgamma, …).
  • Literal syntax — 1.0 + 2.0_e constructs dual<double>(1, 2).
  • fmt support — optional formatters via #define CPPDUALS_LIBFMT.

Quick Example

#include <duals/dual>
using namespace duals::literals;
template <class T>
T f(T x) { return x * sin(x); }
int main() {
auto result = f(2.0 + 1.0_e);
// rpart = f(2) = 2*sin(2) = 1.8186
// dpart = f'(2) = sin(2) + 2*cos(2) = 0.0770
std::cout << result << "\n"; // (1.8186+0.077004_e)
}
dual<T,N> arithmetic and forward-mode automatic differentiation.
Dual number literals.
Definition dual:883

How It Works

The Taylor expansion of \( f(a + b\epsilon) \) truncates at first order:

\[f(a + b\epsilon) = f(a) + f'(a)\,b\,\epsilon \]

Setting \( b = 1 \) places the derivative \( f'(a) \) in the dual part of the result. Higher derivatives are obtained by nesting: dual<dual<T>> carries both \( f' \) and \( f'' \).

Multivariate Differentiation

For functions of multiple variables, duals/multidual provides dual<T, int N> — a dual number carrying N independent partial derivatives. This computes the full gradient \( \nabla f = (\partial f/\partial x_1, \ldots, \partial f/\partial x_N) \) in a single evaluation pass, rather than requiring N separate passes:

#include <duals/multidual>
int main() {
auto x = D3::variable(1.0, 0); // seed df/dx
auto y = D3::variable(2.0, 1); // seed df/dy
auto z = D3::variable(3.0, 2); // seed df/dz
auto f = sin(x * y) + exp(z);
// f.dpart(0) = df/dx, f.dpart(1) = df/dy, f.dpart(2) = df/dz
}

With N=1 (the default), dual<T> and dual<T,1> are identical — all existing code works unchanged.

Headers

Header Purpose
duals/dual Core dual<T> class, math functions, IO, complex overloads
duals/multidual Multivariate dual<T,N> with compile-time gradient support
duals/dual_eigen Eigen NumTraits, type promotion, SIMD packet ops