File Coverage

blib/lib/Math/Symbolic/MiscCalculus.pm
Criterion Covered Total %
statement 73 73 100.0
branch 20 28 71.4
condition n/a
subroutine 9 9 100.0
pod 3 3 100.0
total 105 113 92.9


line stmt bran cond sub pod time code
1              
2             =encoding utf8
3              
4             =head1 NAME
5              
6             Math::Symbolic::MiscCalculus - Miscellaneous calculus routines (eg Taylor poly)
7              
8             =head1 SYNOPSIS
9              
10             use Math::Symbolic qw/:all/;
11             use Math::Symbolic::MiscCalculus qw/:all/; # not loaded by Math::Symbolic
12            
13             $taylor_poly = TaylorPolynomial $function, $degree, $variable;
14             # or:
15             $taylor_poly = TaylorPolynomial $function, $degree, $variable, $pos;
16            
17             $lagrange_error = TaylorErrorLagrange $function, $degree, $variable;
18             # or:
19             $lagrange_error = TaylorErrorLagrange $function, $degree, $variable, $pos;
20             # or:
21             $lagrange_error = TaylorErrorLagrange $function, $degree, $variable, $pos,
22             $name_for_range_variable;
23            
24             # This has the same syntax variations as the Lagrange error:
25             $cauchy_error = TaylorErrorLagrange $function, $degree, $variable;
26              
27             =head1 DESCRIPTION
28              
29             This module provides several subroutines related to
30             calculus such as computing Taylor polynomials and errors the
31             associated errors from Math::Symbolic trees.
32              
33             Please note that the code herein may or may not be refactored into
34             the OO-interface of the Math::Symbolic module in the future.
35              
36             =head2 EXPORT
37              
38             None by default.
39              
40             You may choose to have any of the following routines exported to the
41             calling namespace. ':all' tag exports all of the following:
42              
43             TaylorPolynomial
44             TaylorErrorLagrange
45             TaylorErrorCauchy
46              
47             =head1 SUBROUTINES
48              
49             =cut
50              
51             package Math::Symbolic::MiscCalculus;
52              
53 2     2   3571 use 5.006;
  2         13  
  2         79  
54 2     2   13 use strict;
  2         5  
  2         70  
55 2     2   12 use warnings;
  2         3  
  2         64  
56              
57 2     2   12 use Carp;
  2         4  
  2         156  
58              
59 2     2   10 use Math::Symbolic qw/:all/;
  2         4  
  2         3441  
60              
61             require Exporter;
62             our @ISA = qw(Exporter);
63             our %EXPORT_TAGS = (
64             'all' => [
65             qw(
66             TaylorPolynomial
67             TaylorErrorLagrange
68             TaylorErrorCauchy
69             )
70             ]
71             );
72              
73             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
74              
75             our $VERSION = '0.612';
76              
77             =begin comment
78              
79             _faculty() computes the (symbolic) product that is the faculty of the
80             first argument.
81              
82             =end comment
83              
84             =cut
85              
86             sub _faculty {
87 10     10   20 my $num = shift;
88 10 50       33 croak "Cannot calculate faculty of negative numbers."
89             if $num < 0;
90 10         59 my $fac = Math::Symbolic::Constant->one();
91 10 100       48 return $fac if $num <= 1;
92 7         39 for ( my $i = 2 ; $i <= $num ; $i++ ) {
93 11         60 $fac *= Math::Symbolic::Constant->new($i);
94             }
95 7         37 return $fac;
96             }
97              
98             =head2 TaylorPolynomial
99              
100             This function (symbolically) computes the nth-degree Taylor Polynomial
101             of a given function. Generally speaking, the Taylor Polynomial is an
102             n-th degree polynomial that approximates the original function. It does
103             so particularly well in the proximity of a certain point x0.
104             (Since my mathematical English jargon is lacking, I strongly suggest you
105             read up on what this is in a book.)
106              
107             Mathematically speaking, the Taylor Polynomial of the function f(x) looks
108             like this:
109              
110             Tn(f, x, x0) =
111             sum_from_k=0_to_n(
112             n-th_total_derivative(f)(x0) / k! * (x-x0)^k
113             )
114              
115             First argument to the subroutine must be the function to approximate. It may
116             be given either as a string to be parsed or as a valid Math::Symbolic tree.
117             Second argument must be an integer indicating to which degree to approximate.
118             The third argument is the last required argument and denotes the variable
119             to use for approximation either as a string (name) or as a
120             Math::Symbolic::Variable object. That's the 'x' above.
121             The fourth argument is optional and specifies the name of the variable to
122             introduce as the point of approximation. May also be a variable object.
123             It's the 'x0' above. If not specified, the name of this variable will be
124             assumed to be the name of the function variable (the 'x') with '_0' appended.
125              
126             This routine is for functions of one variable only. There is an equivalent
127             for functions of two variables in the Math::Symbolic::VectorCalculus package.
128              
129             =cut
130              
131             sub TaylorPolynomial ($$$;$) {
132 3     3 1 19 my $func = shift;
133 3         6 my $degree = shift;
134 3         8 my $var = shift;
135 3         6 my $pos = shift;
136              
137 3 50       23 $func = parse_from_string($func)
138             unless ref($func) =~ /^Math::Symbolic/;
139 3 50       80 $var = Math::Symbolic::Variable->new($var)
140             unless ref($var) =~ /^Math::Symbolic::Variable$/;
141 3 50       24 $pos = Math::Symbolic::Variable->new( $var->name() . '_0' )
142             unless ref($pos) =~ /^Math::Symbolic::Variable$/;
143              
144 3         13 my $copy = $func->new();
145 3         10 $copy->implement( $var->name() => $pos );
146 3         20 my $taylor = $copy;
147              
148 3 100       16 return $taylor if $degree == 0;
149              
150 2         10 my $diff = Math::Symbolic::Operator->new( '-', $var, $pos );
151              
152 2         8 my $partial = $func->new();
153 2         7 foreach my $d ( 1 .. $degree ) {
154 4         17 $partial =
155             Math::Symbolic::Operator->new( 'total_derivative', $partial, $var );
156 4         43 $partial = $partial->apply_derivatives()->simplify();
157 4         219 my $copy = $partial->new()->implement( $var->name() => $pos );
158 4         47 $taylor += Math::Symbolic::Operator->new(
159             '*',
160             Math::Symbolic::Operator->new( '/', $copy, _faculty($d) ),
161             Math::Symbolic::Operator->new(
162             '^', $diff, Math::Symbolic::Constant->new($d)
163             )
164             );
165             }
166 2         121 return $taylor;
167             }
168              
169             =head2 TaylorErrorLagrange
170              
171             TaylorErrorLagrange computes and returns the formula for the Taylor
172             Polynomial's approximation error after Lagrange. (Again, my English
173             terminology is lacking.) It looks similar to this:
174              
175             Rn(f, x, x0) =
176             n+1-th_total_derivative(f)( x0 + theta * (x-x0) ) / (n+1)! * (x-x0)^(n+1)
177              
178             Please refer to your favourite book on the topic. 'theta' may be
179             any number between 0 and 1.
180              
181             The calling conventions for TaylorErrorLagrange are similar to those of
182             TaylorPolynomial, but TaylorErrorLagrange takes an extra optional argument
183             specifying the name of 'theta'. If it isn't specified explicitly, the
184             variable will be named 'theta' as in the formula above.
185              
186             =cut
187              
188             sub TaylorErrorLagrange ($$$;$$) {
189 6     6 1 2577 my $func = shift;
190 6         13 my $degree = shift;
191 6         12 my $var = shift;
192 6         13 my $pos = shift;
193 6         13 my $theta = shift;
194              
195 6 100       46 $func = parse_from_string($func)
196             unless ref($func) =~ /^Math::Symbolic/;
197 6 100       119 $var = Math::Symbolic::Variable->new($var)
198             unless ref($var) =~ /^Math::Symbolic::Variable$/;
199 6 100       44 $pos = Math::Symbolic::Variable->new( $var->name() . '_0' )
200             unless ref($pos) =~ /^Math::Symbolic::Variable$/;
201 6 100       39 $theta = Math::Symbolic::Variable->new('theta')
202             unless ref($theta) =~ /^Math::Symbolic::Variable$/;
203              
204 6         28 my $error =
205             Math::Symbolic::Operator->new( 'total_derivative', $func->new(), $var );
206              
207 6         25 foreach ( 1 .. $degree + 1 ) {
208 14         71 $error =
209             Math::Symbolic::Operator->new( 'total_derivative', $error, $var );
210 14         165 $error = $error->apply_derivatives()->simplify();
211             }
212              
213             # We want to avoid endless recursion at all cost!
214 6         33 my @sig = $func->signature();
215 6         26 my $last = $sig[-1] . '_not_taken';
216              
217 6         30 $error->implement( $var->name() => Math::Symbolic::Variable->new($last) );
218 6         85 my $xhi = Math::Symbolic::Operator->new(
219             '+', $pos,
220             Math::Symbolic::Operator->new(
221             '*', $theta, Math::Symbolic::Operator->new( '-', $var, $pos )
222             )
223             );
224 6         30 $error->implement( $last => $xhi );
225              
226 6         73 $error = Math::Symbolic::Operator->new(
227             '*', $error,
228             Math::Symbolic::Operator->new(
229             '/',
230             Math::Symbolic::Operator->new(
231             '^',
232             Math::Symbolic::Operator->new( '-', $var, $pos ),
233             Math::Symbolic::Constant->new( $degree + 1 )
234             ),
235             _faculty( $degree + 1 )
236             )
237             );
238 6         56 return $error;
239             }
240              
241             =head2 TaylorErrorCauchy
242              
243             TaylorErrorCauchy computes and returns the formula for the Taylor
244             Polynomial's approximation error after (guess who!) Cauchy.
245             (Again, my English terminology is lacking.) It looks similar to this:
246              
247             Rn(f, x, x0) = TaylorErrorLagrange(...) * (1 - theta)^n
248              
249             Please refer to your favourite book on the topic and the documentation for
250             TaylorErrorLagrange. 'theta' may be any number between 0 and 1.
251              
252             The calling conventions for TaylorErrorCauchy are identical to those of
253             TaylorErrorLagrange.
254              
255             =cut
256              
257             sub TaylorErrorCauchy ($$$;$$) {
258 3     3 1 2442 my $func = shift;
259 3         8 my $degree = shift;
260 3         7 my $var = shift;
261 3         8 my $pos = shift;
262 3         5 my $theta = shift;
263              
264 3 50       27 $func = parse_from_string($func)
265             unless ref($func) =~ /^Math::Symbolic/;
266 3 50       89 $var = Math::Symbolic::Variable->new($var)
267             unless ref($var) =~ /^Math::Symbolic::Variable$/;
268 3 50       22 $pos = Math::Symbolic::Variable->new( $var->name() . '_0' )
269             unless ref($pos) =~ /^Math::Symbolic::Variable$/;
270 3 50       24 $theta = Math::Symbolic::Variable->new('theta')
271             unless ref($theta) =~ /^Math::Symbolic::Variable$/;
272              
273 3         17 my $error = TaylorErrorLagrange( $func, $degree, $var, $pos, $theta );
274              
275 3         19 $error = Math::Symbolic::Operator->new(
276             '*', $error,
277             Math::Symbolic::Operator->new(
278             '^',
279             Math::Symbolic::Operator->new(
280             '-', Math::Symbolic::Constant->one(), $theta
281             ),
282             $degree
283             )
284             );
285 3         40 return $error;
286             }
287              
288             1;
289             __END__