Added the roadmap

This commit is contained in:
Connor Johnstone
2025-10-23 16:47:48 -04:00
parent 8d4aed4e84
commit e3788bf607
39 changed files with 3888 additions and 0 deletions

View File

@@ -0,0 +1,324 @@
# Feature: Rosenbrock23 Method
## Overview
Rosenbrock23 is a 2nd/3rd order L-stable Rosenbrock-W method designed for stiff ODEs. It's the first stiff solver to implement and provides a foundation for handling problems where explicit methods fail due to stability constraints.
**Key Characteristics:**
- Order: 2(3) - actually 3rd order solution with 2nd order embedded for error
- Stages: 3
- L-stable: Excellent damping of high-frequency oscillations
- Stiff-aware: Can handle stiffness ratios up to ~10^6
- W-method: Uses approximate Jacobian (doesn't need exact)
- Stiff-aware interpolation: 2nd order dense output
## Why This Feature Matters
- **Stiff problems**: Many real-world ODEs are stiff (chemistry, circuit simulation, etc.)
- **Completes basic toolkit**: With DP5/Tsit5 for non-stiff + Rosenbrock23 for stiff, can handle most problems
- **Foundation for auto-switching**: Enables automatic stiffness detection and algorithm selection
- **Widely used**: MATLAB's ode23s is based on this method
## Dependencies
### Required Infrastructure
- **Linear solver** (see feature #18)
- LU factorization for dense systems
- Generic `LinearSolver` trait
- **Jacobian computation** (see feature #19)
- Finite difference approximation
- User-provided analytical Jacobian (optional)
- Auto-diff integration (future)
### Recommended to Implement First
1. Linear solver infrastructure
2. Jacobian computation
3. Then Rosenbrock23
## Implementation Approach
### Mathematical Background
Rosenbrock methods solve:
```
(I - γh*J) * k_i = h*f(y_n + Σa_ij*k_j) + h*J*Σc_ij*k_j
```
Where:
- J is the Jacobian ∂f/∂y
- γ is a method-specific constant
- Stages k_i are computed by solving linear systems
For Rosenbrock23:
- γ = 1/(2 + √2) ≈ 0.2928932188
- 3 stages requiring 3 linear solves per step
- W-method: J can be approximate or outdated
### Algorithm Structure
```rust
struct Rosenbrock23<D> {
a_tol: SVector<f64, D>,
r_tol: f64,
// Tableau coefficients (as constants)
// Linear solver (to be injected or created)
}
```
### Step Procedure
1. Compute or reuse Jacobian J = ∂f/∂y(t_n, y_n)
2. Form W = I - γh*J
3. Factor W (LU decomposition)
4. For each stage i=1,2,3:
- Compute RHS based on previous stages
- Solve W*k_i = RHS
5. Compute solution: y_{n+1} = y_n + b1*k1 + b2*k2 + b3*k3
6. Compute error: err = e1*k1 + e2*k2 + e3*k3
7. Store dense output coefficients
### Tableau Coefficients
From Shampine & Reichelt (1997) - MATLAB's ode23s:
```
γ = 1/(2 + √2)
Stage matrix for ki calculations:
a21 = 1.0
a31 = 1.0
a32 = 0.0
c21 = -1.0707963267948966
c31 = -0.31381995116890154
c32 = 1.3846153846153846
Solution weights:
b1 = 0.5
b2 = 0.5
b3 = 0.0
Error estimate:
d1 = -0.17094382871185335
d2 = 0.17094382871185335
d3 = 0.0
```
### Jacobian Management
Key decisions:
- **When to update J**: Error signal, step rejection, every N steps
- **Finite difference formula**: Forward or central differences
- **Sparsity**: Dense for now, sparse in future
- **Storage**: Cache J and LU factorization
### Linear Solver Integration
```rust
trait LinearSolver<D> {
fn factor(&mut self, matrix: &SMatrix<f64, D, D>) -> Result<(), Error>;
fn solve(&self, rhs: &SVector<f64, D>) -> Result<SVector<f64, D>, Error>;
}
struct DenseLU<D> {
lu: SMatrix<f64, D, D>,
pivots: [usize; D],
}
```
## Implementation Tasks
### Infrastructure (Prerequisites)
- [ ] **Linear solver trait and implementation**
- [ ] Define `LinearSolver` trait
- [ ] Implement dense LU factorization
- [ ] Add solve method
- [ ] Tests for random matrices
- [ ] **Jacobian computation**
- [ ] Forward finite differences: J[i,j] ≈ (f(y + ε*e_j) - f(y)) / ε
- [ ] Epsilon selection (√machine_epsilon * max(|y[j]|, 1))
- [ ] Cache for function evaluations
- [ ] Test on known Jacobians
### Core Algorithm
- [ ] Define `Rosenbrock23` struct
- [ ] Tableau constants
- [ ] Tolerance fields
- [ ] Jacobian update strategy fields
- [ ] Linear solver instance
- [ ] Implement `step()` method
- [ ] Decide if Jacobian update needed
- [ ] Compute J if needed
- [ ] Form W = I - γh*J
- [ ] Factor W
- [ ] Stage 1: Solve for k1
- [ ] Stage 2: Solve for k2
- [ ] Stage 3: Solve for k3
- [ ] Combine for solution
- [ ] Compute error estimate
- [ ] Return (y_next, error, dense_coeffs)
- [ ] Implement `interpolate()` method
- [ ] 2nd order stiff-aware interpolation
- [ ] Uses k1, k2, k3
- [ ] Jacobian update strategy
- [ ] Update on first step
- [ ] Update on step rejection
- [ ] Update if error test suggests (heuristic)
- [ ] Reuse otherwise
- [ ] Implement constants
- [ ] `ORDER = 3`
- [ ] `STAGES = 3`
- [ ] `ADAPTIVE = true`
- [ ] `DENSE = true`
### Integration
- [ ] Add to prelude
- [ ] Module exports
- [ ] Builder pattern for configuration
### Testing
- [ ] **Stiff test: Van der Pol oscillator**
- [ ] μ = 1000 (very stiff)
- [ ] Explicit methods would need 100000+ steps
- [ ] Rosenbrock23 should handle in <1000 steps
- [ ] Verify solution accuracy
- [ ] **Stiff test: Robertson problem**
- [ ] Classic stiff chemistry problem
- [ ] 3 equations, stiffness ratio ~10^11
- [ ] Verify conservation properties
- [ ] Compare to reference solution
- [ ] **L-stability test**
- [ ] Verify method damps oscillations
- [ ] Test problem with large negative eigenvalues
- [ ] Should remain stable with large time steps
- [ ] **Convergence test**
- [ ] Verify 3rd order convergence on smooth problem
- [ ] Use linear test problem
- [ ] Check error scales as h^3
- [ ] **Jacobian update strategy test**
- [ ] Count Jacobian evaluations
- [ ] Verify not recomputing unnecessarily
- [ ] Verify updates when needed
- [ ] **Comparison test**
- [ ] Same stiff problem with explicit method (DP5)
- [ ] DP5 should require far more steps or fail
- [ ] Rosenbrock23 should be efficient
### Benchmarking
- [ ] Van der Pol benchmark (μ = 1000)
- [ ] Robertson problem benchmark
- [ ] Compare to Julia implementation performance
### Documentation
- [ ] Docstring explaining Rosenbrock methods
- [ ] When to use vs explicit methods
- [ ] Stiffness indicators
- [ ] Example with stiff problem
- [ ] Notes on Jacobian strategy
## Testing Requirements
### Van der Pol Oscillator
```rust
// y1' = y2
// y2' = μ(1 - y1²)y2 - y1
// Initial: y1(0) = 2, y2(0) = 0
// μ = 1000 (very stiff)
```
Integrate from t=0 to t=2000.
Expected behavior:
- Explicit method: >100,000 steps or fails
- Rosenbrock23: ~500-2000 steps depending on tolerance
- Should track limit cycle accurately
### Robertson Problem
```rust
// y1' = -0.04*y1 + 1e4*y2*y3
// y2' = 0.04*y1 - 1e4*y2*y3 - 3e7*y2²
// y3' = 3e7*y2²
// Conservation: y1 + y2 + y3 = 1
```
Integrate from t=0 to t=1e11 (log scale output)
Verify:
- Conservation law maintained
- Correct steady-state behavior
- Handles extreme stiffness ratio
## References
1. **Original Method**:
- Shampine, L.F. and Reichelt, M.W. (1997)
- "The MATLAB ODE Suite", SIAM J. Sci. Computing, 18(1), 1-22
- DOI: 10.1137/S1064827594276424
2. **Rosenbrock Methods Theory**:
- Hairer, E. and Wanner, G. (1996)
- "Solving Ordinary Differential Equations II: Stiff and DAE Problems"
- Chapter IV.7
3. **Julia Implementation**:
- `OrdinaryDiffEq.jl/lib/OrdinaryDiffEqRosenbrock/`
- Files: `rosenbrock_perform_step.jl`, `rosenbrock_caches.jl`
4. **W-methods**:
- Steihaug, T. and Wolfbrandt, A. (1979)
- "An attempt to avoid exact Jacobian and nonlinear equations in the numerical solution of stiff differential equations"
- Math. Comp., 33, 521-534
## Complexity Estimate
**Effort**: Large (20-30 hours)
- Linear solver: 8-10 hours
- Jacobian computation: 4-6 hours
- Rosenbrock23 core: 6-8 hours
- Testing and debugging: 6-8 hours
**Risk**: High
- First implicit method - new complexity
- Linear algebra integration
- Numerical stability issues possible
- Jacobian update strategy tuning needed
## Success Criteria
- [ ] Solves Van der Pol (μ=1000) efficiently
- [ ] Solves Robertson problem accurately
- [ ] Demonstrates L-stability
- [ ] Convergence test shows 3rd order
- [ ] Outperforms explicit methods on stiff problems by 10-100x in steps
- [ ] Jacobian reuse strategy effective (not recomputing every step)
- [ ] Documentation complete with stiff problem examples
- [ ] Performance within 2x of Julia implementation
## Future Enhancements
- [ ] User-provided analytical Jacobians
- [ ] Sparse Jacobian support
- [ ] More sophisticated update strategies
- [ ] Rodas4, Rodas5P (higher-order Rosenbrock methods)
- [ ] Krylov linear solvers for large systems