File Coverage

blib/lib/Math/Polynomial/Chebyshev.pm
Criterion Covered Total %
statement 66 66 100.0
branch 17 20 85.0
condition n/a
subroutine 9 9 100.0
pod 3 3 100.0
total 95 98 96.9


line stmt bran cond sub pod time code
1             # -*- coding: utf-8-unix -*-
2              
3             package Math::Polynomial::Chebyshev;
4              
5 2     2   116184 use 5.008;
  2         20  
6 2     2   1032 use utf8;
  2         24  
  2         10  
7 2     2   52 use strict;
  2         4  
  2         31  
8 2     2   9 use warnings;
  2         2  
  2         46  
9              
10 2     2   9 use Carp qw< croak >;
  2         4  
  2         68  
11 2     2   1171 use Math::Polynomial;
  2         16633  
  2         1044  
12              
13             our $VERSION = '0.02';
14             our @ISA = qw< Math::Polynomial >;
15              
16             =pod
17              
18             =encoding UTF-8
19              
20             =head1 NAME
21              
22             Math::Polynomial::Chebyshev - Chebyshev polynomials of the first kind
23              
24             =head1 SYNOPSIS
25              
26             use Math::Polynomial::Chebyshev;
27              
28             # create a Chebyshev polynomial of the first kind of order 7
29             my $p = Math::Polynomial::Chebyshev -> chebyshev(7);
30              
31             # get the location of all extremas
32             my @xe = $p -> extremas();
33              
34             # get the location of all roots
35             my @xn = $p -> roots();
36              
37             # use higher accuracy
38             use Math::BigFloat;
39             Math::BigFloat -> accuracy(60);
40             my $n_mbf = Math::BigFloat -> new(7);
41             my $p_mbf = Math::Polynomial::Chebyshev -> chebyshev($n_mbf);
42              
43             =head1 DESCRIPTION
44              
45             This package extends Math::Polynomial, so each instance polynomial created by
46             this module is a subclass of Math::Polynomial.
47              
48             The Chebyshev polynomials of the first kind are orthogonal with respect to the
49             weight function 1/sqrt(1-x^2).
50              
51             The first Chebyshev polynomials of the first kind are
52              
53             T₀(x) = 1
54             T₁(x) = x
55             T₂(x) = 2 x^2 - 1
56             T₃(x) = 4 x^3 - 3 x
57             T₄(x) = 8 x^4 - 8 x^2 + 1
58             T₅(x) = 16 x^5 - 20 x^3 + 5 x
59             T₆(x) = 32 x^6 - 48 x^4 + 18 x^2 - 1
60             T₇(x) = 64 x^7 - 112 x^5 + 56 x^3 - 7 x
61             T₈(x) = 128 x^8 - 256 x^6 + 160 x^4 - 32 x^2 + 1
62             T₉(x) = 256 x^9 - 576 x^7 + 432 x^5 - 120 x^3 + 9 x
63              
64             =head1 CLASS METHODS
65              
66             =head2 Constructors
67              
68             =over 4
69              
70             =item I
71              
72             Cchebyshev($n)> creates a new polynomial of
73             order C<$n>, where C<$n> is a non-negative integer.
74              
75             # create a Chebyshev polynomial of the first kind of order 7
76             $p = Math::Polynomial::Chebyshev -> chebyshev(7);
77              
78             # do the same, but with Math::BigFloat coefficients
79             use Math::BigFloat;
80             $n = Math::BigFloat -> new(7);
81             $p = Math::Polynomial::Chebyshev -> chebyshev($n);
82              
83             # do the same, but with Math::Complex coefficients
84             use Math::Complex;
85             $n = Math::Complex -> new(7);
86             $p = Math::Polynomial::Chebyshev -> chebyshev($n);
87              
88             =cut
89              
90             sub chebyshev {
91 10     10 1 35254 my $class = shift;
92 10         15 my $n = shift;
93              
94 10 50       23 croak "order must be an integer" unless $n == int $n;
95              
96 10         18 my $zero = $n - $n;
97 10         14 my $one = $n ** 0;
98 10         24 my $two = $one + $one;
99              
100 10         15 my $c = [];
101 10 100       27 if ($n == 0) {
    100          
102 1         3 $c = [ $one ];
103             } elsif ($n == 1) {
104 1         3 $c = [ $zero, $one ];
105             } else {
106 8         15 my $a = [ $one ];
107 8         13 my $b = [ $zero, $one ];
108              
109 8         21 for (my $i = 2 ; $i <= $n ; ++$i) {
110 36         48 $c = [ $zero, map { $two * $_ } @$b ];
  156         216  
111              
112 36         62 for (my $i = 0 ; $i <= $#$a ; ++$i) {
113 120         193 $c -> [$i] -= $a -> [$i];
114             }
115              
116 36         46 $a = $b;
117 36         58 $b = $c;
118             }
119             }
120              
121 10         48 return $class -> new(@$c);
122             }
123              
124             =pod
125              
126             =item I
127              
128             C<$p-Eroots()> returns the location of all root of C<$p>. All roots
129             are located in the open interval (-1,1).
130              
131             # get the roots of a polynomial
132             @x = $p -> roots();
133              
134             =cut
135              
136             sub roots {
137 10     10 1 44670 my $self = shift;
138 10 50       27 croak 'array context required' unless wantarray;
139              
140 10         26 my $n = $self -> degree();
141              
142             # Quick exit for the simple case N = 0.
143              
144 10 100       54 return () if $n == 0;
145              
146             # Quick exit for the simple case N = 1.
147              
148 9         19 my $zero = $self -> coeff_zero();
149 9 100       34 return $zero if $n == 1;
150              
151             # The general case, when N > 0.
152              
153 8         16 my $one = $self -> coeff_one();
154 8         32 my $pi = atan2 $zero, -$one;
155 8         14 my $c = $pi / $n;
156              
157 8         13 my @x = ();
158              
159             # First compute all roots in the open interval (0,1).
160              
161 8         21 @x = map { cos($c * ($_ - 0.5)) } 1 .. int($n / 2);
  20         1326  
162              
163             # Now create an array with all extremas on the closed interval [-1,1].
164              
165 8 100       17 @x = (map({ -$_ } @x),
  20         52  
166             ($n % 2 ? $zero : ()),
167             reverse(@x));
168              
169 8         24 return @x;
170             }
171              
172             =pod
173              
174             =item I
175              
176             C<$p-Eextremas()> returns the location of all extremas of C<$p> located in
177             the closed interval [-1,1]. There are no extremas outside of this interval.
178             Only the extremas in the closed interval (-1,1) are local extremas. All
179             extremas have values +/-1.
180              
181             # get the extremas of a polynomial
182             @x = $p -> extremas();
183              
184             =cut
185              
186             sub extremas {
187 10     10 1 51243 my $self = shift;
188 10 50       26 croak 'array context required' unless wantarray;
189              
190 10         27 my $n = $self -> degree();
191              
192             # Quick exit for the simple case N = 0.
193              
194 10         56 my $zero = $self -> coeff_zero();
195 10 100       37 return $zero if $n == 0;
196              
197             # The general case, when N > 0.
198              
199 9         22 my $one = $self -> coeff_one();
200 9         41 my $pi = atan2 $zero, -$one;
201 9         19 my $c = $pi / $n;
202              
203 9         14 my @x = ();
204              
205             # First compute all extremas in the open interval (0, 1).
206              
207 9         27 @x = map { cos($c * $_) } 1 .. int(($n - 1) / 2);
  16         39  
208              
209             # Now create an array with all extremas on the closed interval [-1,1].
210              
211             @x = (-$one,
212 9 100       30 map({ -$_ } @x),
  16         40  
213             ($n % 2 ? () : $zero),
214             reverse(@x),
215             $one);
216              
217 9         26 return @x;
218             }
219              
220             =pod
221              
222             =back
223              
224             =head1 BUGS
225              
226             Please report any bugs through the web interface at
227             L
228             (requires login). We will be notified, and then you'll automatically be
229             notified of progress on your bug as I make changes.
230              
231             =head1 SUPPORT
232              
233             You can find documentation for this module with the perldoc command.
234              
235             perldoc Math::Polynomial::Chebyshev
236              
237             You can also look for information at:
238              
239             =over 4
240              
241             =item * GitHub Source Repository
242              
243             L
244              
245             =item * RT: CPAN's request tracker
246              
247             L
248              
249             =item * CPAN Ratings
250              
251             L
252              
253             =item * MetaCPAN
254              
255             L
256              
257             =item * CPAN Testers Matrix
258              
259             L
260              
261             =back
262              
263             =head1 SEE ALSO
264              
265             =over
266              
267             =item *
268              
269             The Perl module L.
270              
271             =item *
272              
273             The Wikipedia page L.
274              
275             =back
276              
277             =head1 LICENSE AND COPYRIGHT
278              
279             Copyright (c) 2020 Peter John Acklam.
280              
281             This program is free software; you may redistribute it and/or modify it under
282             the same terms as Perl itself.
283              
284             =head1 AUTHOR
285              
286             Peter John Acklam Epjacklam (at) gmail.comE.
287              
288             =cut
289              
290             1;