Explicit Euler
Routine Name : Explicit Euler Method
Author : Kyle Hovey
Language : C++
Description/Purpose :
This computational method solves an initial value problem of the form
\[y’(t) = f(t, y(t)) \wedge y(t_0) \equiv y_0\]
Input :
The driving function, initial condition, and time step.
Output :
A function that will evaluate to an approximated solution. The returned function also memoizes entries and uses dynamic programming to never compute the same value twice.
Usage/Example :
int main () {
// Domain and range of solution
using D = double ;
// Driving function and initial condition
const auto uInit = 1 ;
const auto dt = 0.01 ;
const driver < D > f = []( const D & t , const D & ut ) -> D {
return t * ut ;
};
// Exact solution
const endo < D > exact = []( const D & t ) -> D {
return std :: exp ( t * t / 2 );
};
// Solve the system
const auto soln = genEulerSolution < D > ( f , dt , uInit );
// Test the solution
for ( auto i = 0 ; i < 10 ; ++ i ) {
std :: cout << "u(" << i * dt << ")" << " vs " ;
std :: cout << exact ( i * dt ) << std :: endl ;
std :: cout << soln ( i * dt ) << std :: endl ;
}
return EXIT_SUCCESS ;
}
Output:
u ( 0 )
1 vs 1
u ( 0.01 )
1.00005 vs 1.0001
u ( 0.02 )
1.0002 vs 1.0003
u ( 0.03 )
1.00045 vs 1.0006
u ( 0.04 )
1.0008 vs 1.001
u ( 0.05 )
1.00125 vs 1.0015
u ( 0.06 )
1.0018 vs 1.0021
u ( 0.07 )
1.00245 vs 1.0028
u ( 0.08 )
1.00321 vs 1.00361
u ( 0.09 )
1.00406 vs 1.00451
Implementation/Code:
#include <iostream>
#include <functional>
#include <cmath>
#include <vector>
template < typename T >
using endo = std :: function < T ( const T & ) > ;
template < typename T >
using driver = std :: function < T ( const T & , const T & ) > ;
/**
* Solve a very basic differential equation using an Explicit Euler technique.
* u' = f(t, u)
* @param {f} RHS of differential equation (utilizes uPrime)
* @param {dt} Differential of time between samples
* (output function will round to these)
* @param {uInit} Initial value of u(0)
* @return Function that gives you the output at time t
*/
template < typename T >
endo < T > genEulerSolution (
const driver < T >& f ,
const T & dt ,
const T & uInit
) {
// Memoization cache
std :: vector < T > cache = { };
cache . push_back ( uInit );
return [ = ]( const T & t ) mutable -> T {
const auto step = std :: floor ( t / dt );
if ( step >= cache . size ()) {
const auto size = cache . size ();
for ( auto i = size ; i <= step ; ++ i ) {
const auto lastVal = cache [ i - 1 ];
cache . push_back ( lastVal + dt * f ( t , lastVal ));
}
}
return cache [ step ];
};
}