# Delay Differential Equations (DDE)
The `dde` module provides tools for solving delay differential equations (DDEs), which are differential equations where the derivative of the unknown function at a certain time depends on the solution at previous times. This module focuses on initial value problems for DDEs (`DDEProblem`).
## Table of Contents
- [Defining a DDE](#defining-a-dde)
- [The History Function](#the-history-function)
- [Solving an Initial Value Problem (DDEProblem)](#solving-an-initial-value-problem)
- [Examples](#examples)
- [Notation](#notation)
## Defining a DDE
The `DDE` trait defines the delay differential equation `dydt = f(t, y(t), y(t - lag_1), ..., y(t - lag_L))` and the lag functions.
### DDE Trait
* `diff(&self, t: T, y: &Y, yd: &[Y; L], dydt: &mut Y)`: Defines the differential equation. `y` is the current state `y(t)`, and `yd` is an array slice containing the delayed states `[y(t - lag_1), ..., y(t - lag_L)]`. `L` is a const generic parameter indicating the number of constant/state-dependent lags.
* `lags(&self, t: T, y: &Y, lags: &mut [T; L])`: Defines the actual time lag values `[lag_1, ..., lag_L]` at time `t` and state `y`. These lags determine the past times `t - lag_i` at which the solution is evaluated.
### Event Trait
For event detection with precise zero-crossing detection, implement the separate `Event` trait:
* `config` - Configure event detection parameters (direction filtering, termination count)
* `event` - Event function `g(t,y)` whose zero crossings are detected using Brent-Dekker root finding
### Solout Trait
The `Solout` trait works similarly to how it does for ODEs, allowing customization of which points are saved in the solution.
### Implementation Example
```rust
use differential_equations::prelude::*;
use nalgebra::Vector3; // Using nalgebra for state vector
// Example: Breast Cancer Model with Delay
// du₁/dt = (v₀ / (1 + β₀ * u₃(t-τ)²)) * (p₀ - q₀) * u₁ - d₀ * u₁
// du₂/dt = (v₀ / (1 + β₀ * u₃(t-τ)²)) * (1 - p₀ + q₀) * u₁ + (v₁ / (1 + β₁ * u₃(t-τ)²)) * (p₁ - q₁) * u₂ - d₁ * u₂
// du₃/dt = (v₁ / (1 + β₁ * u₃(t-τ)²)) * (1 - p₁ + q₁) * u₂ - d₂ * u₃
struct BreastCancerModel {
p0: f64, q0: f64, v0: f64, d0: f64,
p1: f64, q1: f64, v1: f64, d1: f64, d2: f64,
beta0: f64, beta1: f64,
tau: f64, // The time delay
}
// L=1 because there is one delay term, Y is Vector3<f64>
impl DDE<1, f64, Vector3<f64>> for BreastCancerModel {
fn diff(&self, _t: f64, u: &Vector3<f64>, ud: &[Vector3<f64>; 1], dudt: &mut Vector3<f64>) {
// ud[0] corresponds to u(t - lags[0])
// ud[0][2] is u₃(t-τ)
let hist3 = ud[0][2];
let term0_common = self.v0 / (1.0 + self.beta0 * hist3.powi(2));
let term1_common = self.v1 / (1.0 + self.beta1 * hist3.powi(2));
dudt[0] = term0_common * (self.p0 - self.q0) * u[0] - self.d0 * u[0];
dudt[1] = term0_common * (1.0 - self.p0 + self.q0) * u[0]
+ term1_common * (self.p1 - self.q1) * u[1]
- self.d1 * u[1];
dudt[2] = term1_common * (1.0 - self.p1 + self.q1) * u[1] - self.d2 * u[2];
}
fn lags(&self, _t: f64, _y: &Vector3<f64>, lags: &mut [f64; 1]) {
// Define the constant lag
lags[0] = self.tau;
}
}
// Separate event detection implementation
impl Event<f64, Vector3<f64>> for BreastCancerModel {
fn config(&self) -> EventConfig {
EventConfig::new(CrossingDirection::Negative, Some(1)) // Terminate when u1 becomes negative
}
fn event(&self, _t: f64, y: &Vector3<f64>) -> f64 {
// Event function g(t,y) = y[0] - 0.0
// Zero crossing occurs when y[0] = 0.0 (first component becomes negative)
y[0]
}
}
```
Generics `<const L: usize, T, Y>` are used: `L` is the number of discrete lags, `T` is the float type (e.g., `f64`), `Y` is the state vector type, and `D` is the type for event data (defaulting to `String`).
## The History Function
A crucial component for solving DDEs is the **history function**. This function, `phi(t)`, provides the solution `y(t)` for all times `t <= t0`, where `t0` is the initial time of the simulation. The solver uses this function to look up values of `y` at past times when evaluating delayed terms, especially at the beginning of the integration interval.
The history function is provided when creating a `DDEProblem` and should have the signature `Fn(T) -> V`.
```rust
// Example history function: y(t) = initial_state for t <= 0
// For the BreastCancerModel with state Vector3<f64>
let initial_state = Vector3::new(1.0, 1.0, 1.0);
```
Solving Breast Cancer Model (tau=1) from t=0 to t=10...
Solver finished with status: Complete
Function evaluations: 198
Solver steps: 28
Accepted steps: 27
Rejected steps: 1
Number of output points: 21
t: 0.0000, u1: 1.0000, u2: 1.0000, u3: 1.0000
t: 0.5000, u1: 0.0801, u2: 0.6619, u3: 0.7841
t: 1.0000, u1: 0.0064, u2: 0.3972, u3: 0.5856
t: 1.5000, u1: 0.0005, u2: 0.2348, u3: 0.4282
t: 2.0000, u1: 0.0000, u2: 0.1377, u3: 0.3123
t: 2.5000, u1: 0.0000, u2: 0.0802, u3: 0.2253
t: 3.0000, u1: 0.0000, u2: 0.0466, u3: 0.1597
t: 3.5000, u1: -0.0000, u2: 0.0270, u3: 0.1111
t: 4.0000, u1: -0.0000, u2: 0.0156, u3: 0.0758
t: 4.5000, u1: 0.0000, u2: 0.0090, u3: 0.0510
t: 5.0000, u1: -0.0000, u2: 0.0052, u3: 0.0338
t: 5.5000, u1: 0.0000, u2: 0.0030, u3: 0.0222
t: 6.0000, u1: 0.0000, u2: 0.0017, u3: 0.0144
t: 6.5000, u1: 0.0000, u2: 0.0010, u3: 0.0093
t: 7.0000, u1: -0.0000, u2: 0.0006, u3: 0.0060
t: 7.5000, u1: -0.0000, u2: 0.0003, u3: 0.0038
t: 8.0000, u1: 0.0000, u2: 0.0002, u3: 0.0024
t: 8.5000, u1: 0.0000, u2: 0.0001, u3: 0.0015
t: 9.0000, u1: -0.0000, u2: 0.0001, u3: 0.0010
t: 9.5000, u1: -0.0000, u2: 0.0000, u3: 0.0006
t: 10.0000, u1: 0.0000, u2: 0.0000, u3: 0.0004
```
## Examples
For more detailed examples of DDEs, refer to the `examples/dde` directory in the repository. These examples showcase different DDE systems, solver configurations, and usage patterns.
* **Mackey-Glass Equation**: A common benchmark DDE exhibiting chaotic behavior.
* **Breast Cancer Model**: A model of tumor growth with delays in the response of the immune system.
## Notation
This library uses the following notation for DDEs:
- `t`: The independent variable, typically time.
- `y`: The dependent state vector `y(t)`.
- `dydt`: The derivative of `y` with respect to `t`, i.e., `y'(t)`.
- `lags`: An array `[lag_1, ..., lag_L]` containing the time delay values.
- `yd`: An array `[y(t - lag_1), ..., y(t - lag_L)]` containing the state vectors at delayed times.
- `k`: Coefficients or intermediate stages within solver algorithms, often representing approximations to derivatives.
Consistency with this notation is encouraged for any future additions to the DDE module.