Automatic Differentiation

oCAS provides forward-mode automatic differentiation via hyper-dual numbers. This is distinct from symbolic differentiation (diff): it evaluates derivatives numerically alongside the function value, without building or simplifying an expression tree.


Hyper-Dual Numbers

A hyper-dual number extends the scalar field with infinitesimal components ε₁, ε₂, … that satisfy εᵢ² = 0. Arithmetic on these numbers propagates exact first (and optionally higher) partial derivatives through every operation.

oCAS represents them as HyperDual<T> over any coefficient type T that implements the DualCoeff trait. In practice T is typically Rational (the only type with a complete DualCoeff implementation in the standard build).

TypeRole
DualShapeLayout descriptor: variable groupings, multiplication table
HyperDual<T>Concrete dual number with value + derivative slots
DualCoeffTrait: zero, one, arithmetic ops for T
new_first_order(n)Convenience: shape with n first-order components

Quick Start

#![allow(unused)]
fn main() {
use ocas_domain::Rational;
use ocas_domain::dual::{new_first_order, HyperDual};

// First-order dual for 2 variables
let shape = new_first_order::<Rational>(2);

// x = 1 + ε₁ (variable 0, unit coefficient)
let x = HyperDual::variable(&shape, 0, Rational::new(1, 1));
// y = 2 + ε₂ (variable 1, unit coefficient)
let y = HyperDual::variable(&shape, 1, Rational::new(2, 1));

// f = x * y  →  value = 2, ∂f/∂x = 2, ∂f/∂y = 1
let f = x * y;
println!("f    = {}", f.value());           // 2
println!("df/dx = {}", f.deriv(0).unwrap()); // 2
println!("df/dy = {}", f.deriv(1).unwrap()); // 1
}

Available Operations

HyperDual<T> supports the standard arithmetic traits (Add, Sub, Mul, Div, Neg). Each operation propagates derivatives via the precomputed multiplication table in DualShape.

OperationSupported?
+, -, *, /Yes
inv() (multiplicative inverse)Yes
pow / exp / log / trigNo (transcendental functions require DualCoeff extensions not yet implemented)

For transcendental functions, fall back to symbolic differentiation (diff) or compile the expression to a numeric evaluator with auto-diff support (planned post-1.0).


Higher-Order Derivatives

DualShape supports multi-index groupings for higher-order derivatives (e.g., second-order εᵢεⱼ components). Use DualShape::new with nested index vectors for custom shapes, or the first-order convenience function for the common case.


Python & C Usage

Python

from ocas import DualShape, HyperDual

shape = DualShape.first_order(2)
x = HyperDual.variable(shape, 0, 1)
y = HyperDual.variable(shape, 1, 2)

f = x * y
print(f.value())    # 2
print(f.deriv(0))   # 2  (∂f/∂x)
print(f.deriv(1))   # 1  (∂f/∂y)

# Arithmetic dunder methods: __add__, __sub__, __mul__, __truediv__, __neg__
g = x + y * x
print(g.deriv(0))   # 3  (1 + y = 1 + 2)

C

#include <ocas.h>

int err = 0;
struct ocas_OcasDualShape *shape = ocas_dual_shape_new(2, &err);
struct ocas_OcasHyperDual *x = ocas_dual_variable(shape, 0, "1", &err);
struct ocas_OcasHyperDual *y = ocas_dual_variable(shape, 1, "2", &err);

struct ocas_OcasHyperDual *f = ocas_dual_mul(x, y, &err);
char *val = ocas_dual_value(f, &err);    /* "2" */
char *dx  = ocas_dual_deriv(f, 0, &err); /* "2" */

ocas_string_free(val);
ocas_string_free(dx);
ocas_hyperdual_free(f);
ocas_hyperdual_free(y);
ocas_hyperdual_free(x);
ocas_dual_shape_free(shape);

See the Python API and C/C++ API chapters for full documentation.


Limitations

  • Only Rational coefficients are supported in the standard build (no floating-point or finite-field duals yet).
  • Transcendental functions (sin, cos, exp, log, pow) are not yet available on HyperDual.
  • JIT compilation of dual expressions is not yet integrated.