@@ -31,6 +31,8 @@ pub struct FOU<T: FloatExt> {
3131impl < T : FloatExt > FOU < T > {
3232 #[ must_use]
3333 pub fn new ( hurst : T , theta : T , mu : T , sigma : T , n : usize , x0 : Option < T > , t : Option < T > ) -> Self {
34+ assert ! ( n >= 2 , "n must be at least 2" ) ;
35+
3436 Self {
3537 hurst,
3638 theta,
@@ -97,6 +99,35 @@ mod tests {
9799 }
98100 }
99101
102+ #[ test]
103+ fn fou_dt_alignment_holds_for_multiple_grid_sizes ( ) {
104+ let theta = 0.9_f64 ;
105+ let mu = -0.1_f64 ;
106+ let x0 = 0.35_f64 ;
107+ let hs = [ 0.55_f64 , 0.9_f64 ] ;
108+ let ns = [ 3_usize , 17 , 129 , 1000 ] ;
109+ let ts = [ 0.7_f64 , 2.0_f64 ] ;
110+
111+ for & h in & hs {
112+ for & n in & ns {
113+ for & t in & ts {
114+ let p = FOU :: < f64 > :: new ( h, theta, mu, 0.0 , n, Some ( x0) , Some ( t) ) ;
115+ let x = p. sample ( ) ;
116+
117+ let dt = t / ( n as f64 - 1.0 ) ;
118+ let mut expected = x0;
119+ for i in 1 ..n {
120+ expected = expected + theta * ( mu - expected) * dt;
121+ assert ! (
122+ ( x[ i] - expected) . abs( ) < 1e-12 ,
123+ "mismatch at i={i}, n={n}, t={t}, h={h}"
124+ ) ;
125+ }
126+ }
127+ }
128+ }
129+ }
130+
100131 #[ test]
101132 fn fou_sample_is_finite ( ) {
102133 let p = FOU :: < f64 > :: new ( 0.65 , 1.0 , 0.0 , 0.5 , 256 , Some ( 0.1 ) , Some ( 1.0 ) ) ;
0 commit comments