- Reverse mode.
cppODE(..., derivMode = "reverse")computes the gradient of a seeded functional by a discrete adjoint, at a cost that does not grow with the number of parameters."forward-reverse"adds its curvature, the Hessian applied to the tangent, and"forward-forward"the full Hessian. All four methods, events, roots, forcings, the sparse solver and the batch entries are covered.cvode(..., derivMode = "reverse")wraps the CVODES adjoint behind the same interface.keepStore/storereuse a forward pass,errWeightsweights the step size by the adjoint andadjointGridreturns the backward grid. - Derivative names. Arguments and results are called
tangent,hessian,cotangentandcurvature, replacingsens1ini/sens1,sens2ini/sens2,seed/adjointandseedTangent/adjoint2.cppFUN()takestangentX,tangentP,hessianXandhessianP,evaluate()returnsy,tangentandhessian, andvjp()covers both orders.funCpp()is nowcppFUN(); no old name is kept as an alias. - Code generation on an expression graph. The code generator builds a
hash-consed expression graph of the model and differentiates it by automatic
differentiation; SymPy is left for unusual syntax. Generation grows linearly
with the model, long linear sums become tables and regular structure becomes
loops, so models with thousands of states generate and compile in about a
minute.
derivMode = "symbolic"andderivSymb()are gone, and acppFUN()object runs compiled code only. solveODE(..., sensErrCon = FALSE)lets forward sensitivities ride the grid of a value run. Tangent storage is allocated on the heap, without a compile-time limit (nStackis gone).- Bug fixes. Second derivatives through fixed and root events, including
resets and roots that read the clock, agree with forward over forward to
1e-10. The upper half of
$hessianno longer drifts on long stiff runs. Unnamed models no longer repeat their names underset.seed(). The CVODES adjoint converges on models with many parameters and returns its result through the batch. A forcing that multiplies a state compiles,cvode()reads aterminalcolumn given as text, and therb4initial step and time-only sparse Jacobian entries are right. codegenAvailable()reports whether a model can be generated and compiled without installing anything; the examples run only then.- Python 3.9 or newer and R 4.3 or newer are required. The methods vignette covers the reverse mode and benchmarks against CVODES, and every export has an example.
- Bug fix. OpenMP is detected on Windows.
configure.winreadSHLIB_OPENMP_CXXFLAGSfromR_HOME/etc/Makeconf, which on Windows lives under the architecture subdirectory, so every install ran serially and built models without-fopenmp.
- A threaded BLAS no longer deadlocks a forked worker. BLAS is pinned to one
thread for the width of every
fork()and restored in the parent. forkGuard()reports which BLAS cppDE steers, its thread count and whether the handler is installed. The guard is installed when the DLL loads.- The BLAS thread-count probe covers FlexiBLAS and BLIS alongside MKL and OpenBLAS.
- The Windows branch of that probe searched the process image, which exports none of these, so the two-runtime guard did nothing there.
- The package has a
src/, holding the fork guard's entry point.
- A
piecewisetranslates, ascppde::select(cond, a, b). Both branches are evaluated, so each has to be safe to evaluate. &&,||and!are accepted in equations, grouped by Python's parser.- An expression that does not parse names itself and gives a reason.
- A model symbol can no longer collide with an identifier the generator emits.
A parameter named
stdused to rewritestd::powintop[18]::pow. - A symbol named after a C++ keyword compiles,
defaultandintincluded. - A symbol named after a Python keyword is rejected and named, rather than silently renamed. SymPy parses through Python's parser.
- The
doublelocals of a root event'sG_ttlambda are named by position. cppde::value_of(x)is the value accessor across arithmetic types, both dual orders and their expression templates.
- A root event whose crossing falls exactly on an evaluated time now fires. Detection and bisection both tested the sign product strictly.
- A root event no longer fires again on the crossing it just handled.
- A fixed event that makes a root condition true now fires it, with the resets riding on the jump's surface. Terminal conditions are excluded.
- The step size is re-estimated after every event, not only for the multistep methods.
funCpp()substitutes all symbols in one pass. A parameter named after a generated array rewrote the slots already emitted.compile()no longer repeats the OpenMP and KLU flags that the constructors already recorded on the model.inst/examples/example_saltation.Rchecks the sensitivity transport against a SymPy solution to first and second order, over five models.- Generated entry points are dispatched by name and shared object rather than by a cached address, so loading and unloading are without consequence. A model whose library is gone names what it is missing.
- Scoping the lookup to one shared object also stops two models sharing an entry point name from reaching into each other.
clearNativeSymbols()drops the remembered name pairings. It is no longer needed after loading or unloading.
- Test suite over solvers, sensitivities, events, reparametrisation and the batch path.
solveODEBatch()solves many conditions in one.Call, over OpenMP threads, with results identical to the serial path.prepareBatch()andsolveBatch()reuse a validated handle across solves.batchAvailable()reports why a batch would run serially.
./configuredetects SUNDIALS, SuiteSparse/KLU and OpenMP by linking a test binary; a missing library disables only its own feature.install_libs()builds SUNDIALS and SuiteSparse into a per-user cache.
funCpp()compiles algebraic functions with optional derivatives, through forward-mode AD or analytic SymPy derivatives.
solveODE()integrates a model and returns states with first and second order parameter sensitivities.diagnostics()prints the solver statistics.
cppODE()andcvode()generate, compile and load a solver for an ODE system and return a model handle.
compile()builds generated sources throughR CMD SHLIB.- Native symbol lookups are cached;
clearNativeSymbols()drops the cache.
- C++ generation for ODE, CVODE and funCpp models, with common subexpression elimination and Jacobian sparsity detection.
derivSymb()exposes symbolic first and second derivatives through SymPy.
- Event engine with saltation corrections, root finding and PCHIP forcings.
- Rosenbrock4 and Tsit5 single-step steppers with embedded error estimate and dense output.
- Variable-order BDF/NDF and Adams multistep steppers in Nordsieck form, with a Newton corrector.
- AD aware dense LU through LAPACK and sparse LU through KLU.
- Thread-local bump arena and contiguous tangent slab as tangent storage.
dual2nd<T, N>for second order sensitivities.
- Expression templates collapse right-hand side temporaries into one fused chain-rule loop.
- Forward-mode dual numbers
dual<T, N>for first order sensitivities, with a static and a heap allocated specialisation.
- Package skeleton and licence.