Diffid¶
differential identification is a Rust-first toolkit for time-series inference and optimisation with ergonomic Python bindings. It couples high-performance solvers with a highly customisable builder API for identification and optimisation of differential systems.
Why Diffid?¶
Diffid offers a different paradigm for a parameter inference library. Conventionally, Python-based inference libraries are constructed via python bindings to a high-performance forward model with the inference algorithms implemented in Python. Alongside this approach, Diffid introduces an alternative, where the Python layer acts purely as a declarative configuration interface, while all computationally intensive work (the optimisation / sampling loop, gradient calculations, etc.) happens entirely within the Rust runtime without crossing the FFI boundary repeatedly. This is architecture is presented visually below,
Core Capabilities¶
-
Optimisation Algorithms
Gradient-free (Nelder-Mead, CMA-ES) and gradient-based (Adam) optimisers with configurable convergence criteria
-
High-Performance ODE Fitting
Multi-threaded differential equation fitting via DiffSL with dense or sparse Diffsol backends
-
Uncertainty Quantification
Customisable likelihood/cost metrics and Monte-Carlo sampling for posterior exploration
-
Flexible Integration
Integration with state-of-the-art differential solvers: Diffrax, DifferentialEquations.jl
Installation¶
Diffid targets Python >= 3.11. Windows builds are currently marked experimental.
Example: Scalar Optimisation¶
import numpy as np
import diffid
def rosenbrock(x):
value = (1 - x[0]) ** 2 + 100 * (x[1] - x[0] ** 2) ** 2
return np.asarray([value])
builder = (
diffid.ScalarBuilder()
.with_objective(rosenbrock)
.with_parameter("x", 1.5)
.with_parameter("y", -1.5)
)
problem = builder.build()
result = problem.optimise()
print(f"Optimal parameters: {result.x}")
print(f"Objective value: {result.value:.3e}")
print(f"Success: {result.success}")
Example: ODE Fitting¶
import numpy as np
import diffid
# Logistic growth model in DiffSL
dsl = """
in_i {r = 1, k = 1 }
u_i { y = 0.1 }
F_i { (r * y) * (1 - (y / k)) }
"""
t = np.linspace(0.0, 5.0, 51)
observations = np.exp(-1.3 * t)
data = np.column_stack((t, observations))
builder = (
diffid.DiffsolBuilder()
.with_diffsl(dsl)
.with_data(data)
.with_parameter("k", 1.0)
.with_backend("dense")
)
problem = builder.build()
optimiser = diffid.CMAES().with_max_iter(1000)
result = optimiser.run(problem, [0.5, 0.5])
print(result.x)
Next Steps¶
-
Interactive Jupyter notebooks for hands-on learning
-
In-depth guides on choosing and tuning algorithms
-
Visual gallery of example applications
-
Contributing, architecture, and building from source