The complex-step derivative
The entire solver rests on having exact Jacobians: Newton’s method advances by the derivative of the residual, and a derivative corrupted even slightly corrupts every search direction, so an inexact Jacobian is not a small error but a slow, unreliable solve. This document explains the engine that supplies those derivatives exactly and at negligible cost in accuracy and the contract it demands of every residual in return. The method is not a marginal improvement over finite differences; it removes their defining weakness entirely, delivering machine-precision derivatives for a step so small that the truncation error vanishes.
The one price is a discipline on how residuals are written — they must be complex-analytic — which is enforced by the smoothness contract and checked by a roll-call test.
The finite-difference dilemma
A derivative approximated by a finite difference must balance two errors that pull in opposite directions as the step h shrinks. A central difference has a truncation error that falls as h^2, which argues for a small step; but it also subtracts two nearly equal numbers, R(x+h) - R(x-h), and that subtraction amplifies floating-point round-off as \varepsilon_{\text{mach}}/h, which argues for a large one. The total error is therefore minimized at an intermediate step and cannot be driven below an irreducible floor, given for the central difference as:
\text{error} \;\sim\; C_1 h^2 + \frac{C_2\,\varepsilon_{\text{mach}}}{h},
\qquad
\text{minimized near } h \sim \varepsilon_{\text{mach}}^{1/3},
where \varepsilon_{\text{mach}} \approx 2.2\times10^{-16} is the machine epsilon and C_1, C_2 depend on the function’s derivatives. The best attainable relative accuracy is around 10^{-10} to 10^{-8}, worse for an automated solver, and the optimal h depends on the unknown magnitude of the higher derivatives, so no fixed step is safe across the whole state space.
Validation
Because the derivative is meant to be exact, its validation is stringent: the assembled complex-step Jacobian is checked against a finite-difference Jacobian to tolerance, both at the operating point and away from it, and every residual is verified to be continuously differentiable through the zero-flow state on every edge (tests: test_cs_jacobian_matches_finite_difference, test_cs_jacobian_matches_fd_off_operating_point, test_residual_c1_through_zero_flow_all_edges).
The complex-step engine is thus the reason the Jacobian is never itself a source of error. The discipline it demands, analyticity of every residual, is set out in the smoothness contract; the machinery that assembles the complex-stepped kernels into a sparse operator is assembly.
Back to top