File Coverage

blib/lib/Algorithm/Burg.pm
Criterion Covered Total %
statement 59 59 100.0
branch 3 6 50.0
condition 1 6 16.6
subroutine 9 9 100.0
pod 2 2 100.0
total 74 82 90.2


line stmt bran cond sub pod time code
1             package Algorithm::Burg;
2             # ABSTRACT: extrapolate time series using Burg's method
3              
4              
5 3     3   55886 use strict;
  3         7  
  3         127  
6 3     3   14 use warnings qw(all);
  3         5  
  3         123  
7              
8 3     3   13 use Carp qw(croak);
  3         8  
  3         234  
9 3     3   19 use List::Util qw(sum);
  3         5  
  3         319  
10              
11 3     3   1893 use Moo;
  3         181419  
  3         17  
12 3         249 use MooX::Types::MooseLike::Base qw(
13             ArrayRef
14             Num
15 3     3   5815 );
  3         15798  
16 3         1536 use MooX::Types::MooseLike::Numeric qw(
17             PositiveInt
18 3     3   1656 );
  3         2919  
19              
20             our $VERSION = '0.001'; # VERSION
21              
22              
23             has coefficients => (is => 'rwp', isa => ArrayRef[Num]);
24              
25              
26             has order => (is => 'ro', isa => PositiveInt, required => 1);
27              
28              
29             has series_tail => (is => 'rwp', isa => ArrayRef[Num]);
30              
31              
32             sub train {
33 2     2 1 4374 my ($self, $time_series) = @_;
34              
35 2 50       13 croak '$time_series should be an ArrayRef'
36             if ref($time_series) ne 'ARRAY';
37              
38 2         11 my $m = $self->order;
39 2         27 my @x = @$time_series;
40              
41 2 50       9 croak '$time_series should have more elements than the AR order is'
42             if $#x < $m;
43              
44             # initialize Ak
45 2         13 my @Ak = (1.0, (0.0) x $m);
46              
47             # initialize f and b
48 2         26 my @f = @$time_series;
49 2         17 my @B = @$time_series;
50              
51             # Initialize Dk
52 193         255 my $Dk = sum map {
53 2         13 2.0 * $f[$_] ** 2
54             } 0 .. $#f;
55 2         16 $Dk -= $f[0] ** 2 + $B[$#x] ** 2;
56              
57             # Burg recursion
58 2         12 for my $k (0 .. $m - 1) {
59             # compute mu
60 2582         3223 my $mu = sum map {
61 68         204 $f[$_ + $k + 1] * $B[$_]
62             } 0 .. $#x - $k - 1;
63 68         190 $mu *= -2.0 / $Dk;
64              
65             # update Ak
66 68         110 for my $n (0 .. ($k + 1) / 2) {
67 1096         1478 my $t1 = $Ak[$n] + $mu * $Ak[$k + 1 - $n];
68 1096         6294 my $t2 = $Ak[$k + 1 - $n] + $mu * $Ak[$n];
69 1096         982 $Ak[$n] = $t1;
70 1096         1448 $Ak[$k + 1 - $n] = $t2;
71             }
72              
73             # update f and b
74 68         125 for my $n (0 .. $#x - $k - 1) {
75 2582         2798 my $t1 = $f[$n + $k + 1] + $mu * $B[$n];
76 2582         2752 my $t2 = $B[$n] + $mu * $f[$n + $k + 1];
77 2582         2298 $f[$n + $k + 1] = $t1;
78 2582         2583 $B[$n] = $t2;
79             }
80              
81             # update Dk
82 68         197 $Dk = (1.0 - $mu ** 2) * $Dk
83             - $f[$k + 1] ** 2
84             - $B[$#x - $k - 1] ** 2;
85             }
86              
87 2         32 $self->_set_series_tail([ @x[$#x - $m .. $#x] ]);
88 2         2302 return $self->_set_coefficients([ @Ak[1 .. $#Ak] ]);
89             }
90              
91              
92             sub predict {
93 1     1 1 1517 my ($self, $n) = @_;
94              
95 1         6 my $coeffs = $self->coefficients;
96 1         28 my $m = $self->order;
97 1 50 0     13 $n ||= $m
      33        
98             if !$n || $n > $m;
99              
100 1         2 my @predicted = @{ $self->series_tail };
  1         13  
101 1         4 for my $i ($m .. $m + $n) {
102 4160         6201 $predicted[$i] = -1.0 * sum map {
103 65         267 $coeffs->[$_] * $predicted[$i - 1 - $_]
104             } 0 .. $m - 1;
105             }
106              
107 1         31 return [ @predicted[$m .. $#predicted] ];
108             }
109              
110              
111             1;
112              
113             __END__