11use impl_new_derive:: ImplNew ;
2- use ndarray:: { array, Array1 } ;
2+ use ndarray:: { array, s , Array1 } ;
33use statrs:: function:: gamma:: gamma;
44use std:: f64:: consts:: SQRT_2 ;
55
6+ use crate :: stochastic:: { noise:: fgn:: FGN , Sampling } ;
7+
8+ // Version 1: FOUParameterEstimationV1 with linear filter methods
69#[ derive( ImplNew ) ]
7- pub struct FOUParameterEstimation {
10+ pub struct FOUParameterEstimationV1 {
811 pub path : Array1 < f64 > ,
9- pub T : f64 ,
1012 pub filter_type : FilterType ,
1113 // Estimated parameters
1214 hurst : Option < f64 > ,
@@ -26,7 +28,7 @@ pub enum FilterType {
2628 Classical ,
2729}
2830
29- impl FOUParameterEstimation {
31+ impl FOUParameterEstimationV1 {
3032 pub fn estimate_parameters ( & mut self ) -> ( f64 , f64 , f64 , f64 ) {
3133 self . linear_filter ( ) ;
3234 self . hurst_estimator ( ) ;
@@ -86,7 +88,7 @@ impl FOUParameterEstimation {
8688 let denominator = sigma. powi ( 2 ) * gamma ( 2.0 * hurst + 1.0 ) ;
8789 let theta = ( numerator / denominator) . powf ( -1.0 / ( 2.0 * hurst) ) ;
8890
89- self . theta = Some ( theta / self . T ) ;
91+ self . theta = Some ( theta) ;
9092 }
9193
9294 fn linear_filter ( & mut self ) {
@@ -138,7 +140,6 @@ impl FOUParameterEstimation {
138140 }
139141
140142 fn lfilter ( & self , b : & Array1 < f64 > , a : & Array1 < f64 > , x : & Array1 < f64 > ) -> Array1 < f64 > {
141- // Implementing the difference equation: y[n] = b[0]*x[n] + b[1]*x[n-1] + ... - a[1]*y[n-1] - ...
142143 let n = x. len ( ) ;
143144 let mut y = Array1 :: < f64 > :: zeros ( n) ;
144145
@@ -161,20 +162,268 @@ impl FOUParameterEstimation {
161162 }
162163}
163164
165+ // Version 2: FOUParameterEstimationV2 without linear filters
166+ #[ derive( ImplNew ) ]
167+ pub struct FOUParameterEstimationV2 {
168+ pub path : Array1 < f64 > ,
169+ pub delta : f64 ,
170+ pub series_length : usize ,
171+ // Estimated parameters
172+ hurst : Option < f64 > ,
173+ sigma : Option < f64 > ,
174+ mu : Option < f64 > ,
175+ theta : Option < f64 > ,
176+ }
177+
178+ impl FOUParameterEstimationV2 {
179+ pub fn estimate_parameters ( & mut self ) -> ( f64 , f64 , f64 , f64 ) {
180+ self . hurst_estimator ( ) ;
181+ self . sigma_estimator ( ) ;
182+ self . mu_estimator ( ) ;
183+ self . theta_estimator ( ) ;
184+
185+ (
186+ self . hurst . unwrap ( ) ,
187+ self . sigma . unwrap ( ) ,
188+ self . mu . unwrap ( ) ,
189+ self . theta . unwrap ( ) ,
190+ )
191+ }
192+
193+ fn hurst_estimator ( & mut self ) {
194+ let X = & self . path ;
195+ let N = self . series_length ;
196+
197+ let sum1: f64 = ( 0 ..( N - 4 ) )
198+ . map ( |i| {
199+ let diff = X [ i + 4 ] - 2.0 * X [ i + 2 ] + X [ i] ;
200+ diff * diff
201+ } )
202+ . sum ( ) ;
203+
204+ let sum2: f64 = ( 0 ..( N - 2 ) )
205+ . map ( |i| {
206+ let diff = X [ i + 2 ] - 2.0 * X [ i + 1 ] + X [ i] ;
207+ diff * diff
208+ } )
209+ . sum ( ) ;
210+
211+ let estimated_hurst = 0.5 * ( sum1 / sum2) . log2 ( ) ;
212+ self . hurst = Some ( estimated_hurst) ;
213+ }
214+
215+ fn sigma_estimator ( & mut self ) {
216+ let H = self . hurst . unwrap ( ) ;
217+ let X = & self . path ;
218+ let N = self . series_length as f64 ;
219+ let delta = self . delta ;
220+
221+ let numerator: f64 = ( 0 ..( self . series_length - 2 ) )
222+ . map ( |i| {
223+ let diff = X [ i + 2 ] - 2.0 * X [ i + 1 ] + X [ i] ;
224+ diff * diff
225+ } )
226+ . sum ( ) ;
227+
228+ let denominator = N * ( 4.0 - 2.0_f64 . powf ( 2.0 * H ) ) * delta. powf ( 2.0 * H ) ;
229+ let estimated_sigma = ( numerator / denominator) . sqrt ( ) ;
230+ self . sigma = Some ( estimated_sigma) ;
231+ }
232+
233+ fn mu_estimator ( & mut self ) {
234+ let mean = self . path . mean ( ) . unwrap ( ) ;
235+ self . mu = Some ( mean) ;
236+ }
237+
238+ fn theta_estimator ( & mut self ) {
239+ let X = & self . path ;
240+ let H = self . hurst . unwrap ( ) ;
241+ let N = self . series_length as f64 ;
242+ let sigma = self . sigma . unwrap ( ) ;
243+
244+ let sum_X_squared = X . mapv ( |x| x * x) . sum ( ) ;
245+ let sum_X = X . sum ( ) ;
246+ let numerator = N * sum_X_squared - sum_X. powi ( 2 ) ;
247+ let denominator = N . powi ( 2 ) * sigma. powi ( 2 ) * H * gamma ( 2.0 * H ) ;
248+
249+ let estimated_theta = ( numerator / denominator) . powf ( -1.0 / ( 2.0 * H ) ) ;
250+ self . theta = Some ( estimated_theta) ;
251+ }
252+ }
253+
254+ // Version 3: FOUParameterEstimationV3 with get_path method
255+ pub struct FOUParameterEstimationV3 {
256+ alpha : f64 ,
257+ mu : f64 ,
258+ sigma : f64 ,
259+ initial_value : f64 ,
260+ T : f64 ,
261+ delta : f64 ,
262+ series_length : usize ,
263+ hurst : f64 ,
264+ path : Option < Array1 < f64 > > ,
265+ // Estimated parameters
266+ estimated_hurst : Option < f64 > ,
267+ estimated_sigma : Option < f64 > ,
268+ estimated_mu : Option < f64 > ,
269+ estimated_alpha : Option < f64 > ,
270+ }
271+
272+ impl FOUParameterEstimationV3 {
273+ pub fn new (
274+ series_length : usize ,
275+ hurst : f64 ,
276+ sigma : f64 ,
277+ alpha : f64 ,
278+ mu : f64 ,
279+ initial_value : f64 ,
280+ T : f64 ,
281+ delta : f64 ,
282+ ) -> Self {
283+ FOUParameterEstimationV3 {
284+ alpha,
285+ mu,
286+ sigma,
287+ initial_value,
288+ T ,
289+ delta,
290+ series_length,
291+ hurst,
292+ path : None ,
293+ estimated_hurst : None ,
294+ estimated_sigma : None ,
295+ estimated_mu : None ,
296+ estimated_alpha : None ,
297+ }
298+ }
299+
300+ pub fn estimate_parameters ( & mut self ) -> ( f64 , f64 , f64 , f64 ) {
301+ self . get_path ( ) ;
302+ self . hurst_estimator ( ) ;
303+ self . sigma_estimator ( ) ;
304+ self . mu_estimator ( ) ;
305+ self . alpha_estimator ( ) ;
306+
307+ (
308+ self . estimated_hurst . unwrap ( ) ,
309+ self . estimated_sigma . unwrap ( ) ,
310+ self . estimated_mu . unwrap ( ) ,
311+ self . estimated_alpha . unwrap ( ) ,
312+ )
313+ }
314+
315+ fn get_path ( & mut self ) {
316+ let M = 8 ;
317+ let gamma = self . delta / M as f64 ;
318+
319+ let fgn_length = self . series_length * M ;
320+
321+ // Generate fGN sample of length fgn_length
322+ let fgn = FGN :: new ( self . hurst , fgn_length - 1 , Some ( self . T ) , None ) ;
323+ let fgn_sample = fgn. sample ( ) ;
324+
325+ // Initialize full_fou array
326+ let mut full_fou = Array1 :: < f64 > :: zeros ( fgn_length) ;
327+ full_fou[ 0 ] = self . initial_value ;
328+
329+ for i in 1 ..fgn_length {
330+ full_fou[ i] = full_fou[ i - 1 ]
331+ + self . alpha * ( self . mu - full_fou[ i - 1 ] ) * gamma
332+ + self . sigma * fgn_sample[ i - 1 ] ;
333+ }
334+
335+ // Initialize fou array
336+ let mut fou = Array1 :: < f64 > :: zeros ( self . series_length ) ;
337+ fou[ 0 ] = self . initial_value ;
338+
339+ for i in 1 ..self . series_length {
340+ let start = ( i - 1 ) * M ;
341+ let end = i * M ;
342+
343+ let sum_sub_series: f64 = full_fou. slice ( s ! [ start..end] ) . sum ( ) * gamma / M as f64 ;
344+ fou[ i] = full_fou[ end - 1 ] + self . alpha * sum_sub_series;
345+ }
346+
347+ // Store the path
348+ self . path = Some ( fou) ;
349+ }
350+
351+ fn hurst_estimator ( & mut self ) {
352+ let X = self . path . as_ref ( ) . unwrap ( ) ;
353+ let N = self . series_length ;
354+
355+ let sum1: f64 = ( 0 ..( N - 4 ) )
356+ . map ( |i| {
357+ let diff = X [ i + 4 ] - 2.0 * X [ i + 2 ] + X [ i] ;
358+ diff * diff
359+ } )
360+ . sum ( ) ;
361+
362+ let sum2: f64 = ( 0 ..( N - 2 ) )
363+ . map ( |i| {
364+ let diff = X [ i + 2 ] - 2.0 * X [ i + 1 ] + X [ i] ;
365+ diff * diff
366+ } )
367+ . sum ( ) ;
368+
369+ let estimated_hurst = 0.5 * ( sum1 / sum2) . log2 ( ) ;
370+ self . estimated_hurst = Some ( estimated_hurst) ;
371+ }
372+
373+ fn sigma_estimator ( & mut self ) {
374+ let H = self . estimated_hurst . unwrap ( ) ;
375+ let X = self . path . as_ref ( ) . unwrap ( ) ;
376+ let N = self . series_length as f64 ;
377+ let delta = self . delta ;
378+
379+ let numerator: f64 = ( 0 ..( self . series_length - 2 ) )
380+ . map ( |i| {
381+ let diff = X [ i + 2 ] - 2.0 * X [ i + 1 ] + X [ i] ;
382+ diff * diff
383+ } )
384+ . sum ( ) ;
385+
386+ let denominator = N * ( 4.0 - 2.0_f64 . powf ( 2.0 * H ) ) * delta. powf ( 2.0 * H ) ;
387+ let estimated_sigma = ( numerator / denominator) . sqrt ( ) ;
388+ self . estimated_sigma = Some ( estimated_sigma) ;
389+ }
390+
391+ fn mu_estimator ( & mut self ) {
392+ let X = self . path . as_ref ( ) . unwrap ( ) ;
393+ let mean = X . mean ( ) . unwrap ( ) ;
394+ self . estimated_mu = Some ( mean) ;
395+ }
396+
397+ fn alpha_estimator ( & mut self ) {
398+ let X = self . path . as_ref ( ) . unwrap ( ) ;
399+ let H = self . estimated_hurst . unwrap ( ) ;
400+ let N = self . series_length as f64 ;
401+ let sigma = self . estimated_sigma . unwrap ( ) ;
402+
403+ let sum_X_squared = X . mapv ( |x| x * x) . sum ( ) ;
404+ let sum_X = X . sum ( ) ;
405+ let numerator = N * sum_X_squared - sum_X. powi ( 2 ) ;
406+ let denominator = N . powi ( 2 ) * sigma. powi ( 2 ) * H * gamma ( 2.0 * H ) ;
407+
408+ let estimated_alpha = ( numerator / denominator) . powf ( -1.0 / ( 2.0 * H ) ) ;
409+ self . estimated_alpha = Some ( estimated_alpha) ;
410+ }
411+ }
412+
164413#[ cfg( test) ]
165414mod tests {
166415 use super :: * ;
167416 use crate :: stochastic:: { diffusion:: fou:: FOU , noise:: fgn:: FGN , Sampling } ;
168417
169418 #[ test]
170- fn test_fou_parameter_estimation ( ) {
419+ fn test_fou_parameter_estimation_v1 ( ) {
171420 const N : usize = 10000 ;
172421 const X0 : f64 = 0.0 ;
173422
174- let fgn = FGN :: new ( 0.75 , 1599 , Some ( 1.0 ) , None ) ;
175- let fou = FOU :: new ( 3 .0, 5.0 , 3 .0, 1600 , Some ( X0 ) , Some ( 16.0 ) , None , fgn) ;
423+ let fgn = FGN :: new ( 0.70 , 4095 , Some ( 1.0 ) , None ) ;
424+ let fou = FOU :: new ( 5 .0, 2.8 , 1 .0, 4096 , Some ( X0 ) , Some ( 16.0 ) , None , fgn) ;
176425 let path = fou. sample ( ) ;
177- let mut estimator = FOUParameterEstimation :: new ( path, 1.0 , FilterType :: Daubechies ) ;
426+ let mut estimator = FOUParameterEstimationV1 :: new ( path, FilterType :: Daubechies ) ;
178427
179428 // Estimate the parameters
180429 let ( estimated_hurst, estimated_sigma, estimated_mu, estimated_theta) =
@@ -185,13 +434,60 @@ mod tests {
185434 println ! ( "Estimated sigma: {}" , estimated_sigma) ;
186435 println ! ( "Estimated mu: {}" , estimated_mu) ;
187436 println ! ( "Estimated theta: {}" , estimated_theta) ;
437+ }
188438
189- // Assert that the estimated parameters are close to the original ones
190- let tolerance = 0.1 ; // Adjust tolerance as needed
439+ #[ test]
440+ fn test_fou_parameter_estimation_v2 ( ) {
441+ const N : usize = 4096 ;
442+ const X0 : f64 = 0.0 ;
443+ let delta = 1.0 / 256.0 ;
444+
445+ let fgn = FGN :: new ( 0.70 , N - 1 , Some ( 1.0 ) , None ) ;
446+ let fou = FOU :: new ( 5.0 , 2.8 , 2.0 , N , Some ( X0 ) , Some ( 16.0 ) , None , fgn) ;
447+ let path = fou. sample ( ) ;
448+ let mut estimator = FOUParameterEstimationV2 :: new ( path, delta, N ) ;
191449
192- assert ! ( ( estimated_hurst - 0.75 ) . abs( ) < tolerance) ;
193- assert ! ( ( estimated_sigma - 2.0 ) . abs( ) < tolerance) ;
194- assert ! ( ( estimated_mu - 3.0 ) . abs( ) < tolerance) ;
195- assert ! ( ( estimated_theta - 2.0 ) . abs( ) < tolerance) ;
450+ // Estimate the parameters
451+ let ( estimated_hurst, estimated_sigma, estimated_mu, estimated_theta) =
452+ estimator. estimate_parameters ( ) ;
453+
454+ // Print the estimated parameters
455+ println ! ( "Estimated Hurst exponent: {}" , estimated_hurst) ;
456+ println ! ( "Estimated sigma: {}" , estimated_sigma) ;
457+ println ! ( "Estimated mu: {}" , estimated_mu) ;
458+ println ! ( "Estimated theta: {}" , estimated_theta) ;
459+ }
460+
461+ #[ test]
462+ fn test_fou_parameter_estimation_v3 ( ) {
463+ let series_length = 4096 ;
464+ let hurst = 0.70 ;
465+ let sigma = 2.0 ;
466+ let alpha = 5.0 ;
467+ let mu = 2.8 ;
468+ let initial_value = 0.0 ;
469+ let T = 16.0 ;
470+ let delta = 1.0 / 256.0 ;
471+
472+ let mut estimator = FOUParameterEstimationV3 :: new (
473+ series_length,
474+ hurst,
475+ sigma,
476+ alpha,
477+ mu,
478+ initial_value,
479+ T ,
480+ delta,
481+ ) ;
482+
483+ // Estimate the parameters
484+ let ( estimated_hurst, estimated_sigma, estimated_mu, estimated_alpha) =
485+ estimator. estimate_parameters ( ) ;
486+
487+ // Print the estimated parameters
488+ println ! ( "Estimated Hurst exponent: {}" , estimated_hurst) ;
489+ println ! ( "Estimated sigma: {}" , estimated_sigma) ;
490+ println ! ( "Estimated mu: {}" , estimated_mu) ;
491+ println ! ( "Estimated alpha: {}" , estimated_alpha) ;
196492 }
197493}
0 commit comments