line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# ########################################################################################
|
2
|
|
|
|
|
|
|
# A CALCULUS DIFFERENTIATION OBJECT
|
3
|
|
|
|
|
|
|
# An implementation of algebraic differentiation by Jonathan Worthington.
|
4
|
|
|
|
|
|
|
# Copyright (C) Jonathan Worthington 2004
|
5
|
|
|
|
|
|
|
# This module may be used and distributed under the same terms as Perl.
|
6
|
|
|
|
|
|
|
# ########################################################################################
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package Math::Calculus::Differentiate;
|
9
|
1
|
|
|
1
|
|
6406
|
use 5.006;
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
41
|
|
10
|
1
|
|
|
1
|
|
1456
|
use Math::Calculus::Expression;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use strict;
|
12
|
|
|
|
|
|
|
our $VERSION = '0.3';
|
13
|
|
|
|
|
|
|
our @ISA = qw/Math::Calculus::Expression/;
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Math::Calculus::Differentiate - Algebraic Differentiation Engine
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use Math::Calculus::Differentiate;
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# Create an object.
|
24
|
|
|
|
|
|
|
my $exp = Math::Calculus::Differentiate->new;
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Set a variable and expression.
|
27
|
|
|
|
|
|
|
$exp->addVariable('x');
|
28
|
|
|
|
|
|
|
$exp->setExpression('x^2 + 5*x') or die $exp->getError;
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Differentiate and simplify.
|
31
|
|
|
|
|
|
|
$exp->differentiate or die $exp->getError;;
|
32
|
|
|
|
|
|
|
$exp->simplify or die $exp->getError;;
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Print the result.
|
35
|
|
|
|
|
|
|
print $exp->getExpression; # Prints 2*x + 5
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
This module can take an algebraic expression, parse it into a tree structure, modify
|
41
|
|
|
|
|
|
|
the tree to give a representation of the differentiated function, simplify the tree
|
42
|
|
|
|
|
|
|
and turn the tree back into an output of the same form as the input.
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
It supports differentiation of expressions including the +, -, *, / and ^ (raise to
|
45
|
|
|
|
|
|
|
power) operators, bracketed expressions to enable correct precedence and the functions
|
46
|
|
|
|
|
|
|
ln, exp, sin, cos, tan, sec, cosec, cot, sinh, cosh, tanh, sech, cosech, coth, asin,
|
47
|
|
|
|
|
|
|
acos, atan, asinh, acosh and atanh.
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=head1 EXPORT
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
None by default.
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head1 METHODS
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=item new
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
$exp = Math::Calculus::Differentiate->new;
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Creates a new instance of the differentiation engine, which can hold an individual
|
60
|
|
|
|
|
|
|
expression.
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=item addVariable
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
$exp->addVariable('x');
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Sets a certain named value in the expression as being a variable. A named value must be
|
67
|
|
|
|
|
|
|
an alphabetic chracter.
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=item setExpression
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$exp->setExpression('x^2 + 5*x);
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Takes an expression in human-readable form and stores it internally as a tree structure,
|
74
|
|
|
|
|
|
|
checking it is a valid expression that the module can understand in the process. Note that
|
75
|
|
|
|
|
|
|
the engine is strict about syntax. For example, note above that you must write 5*x and not
|
76
|
|
|
|
|
|
|
just 5x. Whitespace is allowed in the expression, but does not have any effect on precedence.
|
77
|
|
|
|
|
|
|
If you require control of precedence, use brackets; bracketed expressions will always be
|
78
|
|
|
|
|
|
|
evaluated first, as you would normally expect. The module follows the BODMAS precedence
|
79
|
|
|
|
|
|
|
convention. Returns undef on failure and a true value on success.
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item getExpression
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
$expr = $exp->getExpression;
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Returns a textaul, human readable representation of the expression that is being stored.
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=cut
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Differentiate.
|
91
|
|
|
|
|
|
|
# ##############
|
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=item differentiate
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
$exp->differentiate('x');
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Differentiates the expression that was stored with setExpression with respect to the variable
|
98
|
|
|
|
|
|
|
passed as a parameter. Returns undef on failure and a true value on success.
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub differentiate {
|
103
|
|
|
|
|
|
|
# Get invocant and variable.
|
104
|
|
|
|
|
|
|
my ($self, $variable) = @_;
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# Check variable is in the list of variables.
|
107
|
|
|
|
|
|
|
return undef unless grep { $_ eq $variable } @{$self->{'variables'}};
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Clear error and traceback, and pass control to the differentiate routine.
|
110
|
|
|
|
|
|
|
$self->{'error'} = $self->{'traceback'} = undef;
|
111
|
|
|
|
|
|
|
eval {
|
112
|
|
|
|
|
|
|
$self->{'expression'} = $self->differentiateTree($variable, $self->{'expression'});
|
113
|
|
|
|
|
|
|
};
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Return an appropriate value (or lack thereof...).
|
116
|
|
|
|
|
|
|
if ($self->{'error'}) {
|
117
|
|
|
|
|
|
|
return undef;
|
118
|
|
|
|
|
|
|
} else {
|
119
|
|
|
|
|
|
|
return 1;
|
120
|
|
|
|
|
|
|
}
|
121
|
|
|
|
|
|
|
}
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=item simplify
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
$exp->simplify;
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Attempts to simplify the expression that is stored internally. It is a very good idea to call
|
129
|
|
|
|
|
|
|
this after calling differentiate, as the tree will often not be in the most compact possible
|
130
|
|
|
|
|
|
|
form, and this will affect the readability of output from getExpression and the performance
|
131
|
|
|
|
|
|
|
of future calls to differentiate if you are intending to obtain higher derivatives. Returns
|
132
|
|
|
|
|
|
|
undef on failure and a true value on success.
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item getTraceback
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
$exp->getTraceback;
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
When setExpression and differentiate are called, a traceback is generated to describe
|
139
|
|
|
|
|
|
|
what these functions did. If an error occurs, this traceback can be extremely useful
|
140
|
|
|
|
|
|
|
in helping track down the source of the error.
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=item getError
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
$exp->getError;
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
When any method other than getTraceback is called, the error message stored is cleared, and
|
147
|
|
|
|
|
|
|
then any errors that occur during the execution of the method are stored. If failure occurs,
|
148
|
|
|
|
|
|
|
call this method to get a textual representation of the error.
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head1 SEE ALSO
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
The author of this module has a website at L, which has
|
153
|
|
|
|
|
|
|
the latest news about the module and a web-based frontend to allow you to test the module
|
154
|
|
|
|
|
|
|
out for yourself.
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 AUTHOR
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Jonathan Worthington, Ejonathan@jwcs.netE
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Copyright (C) 2004 by Jonathan Worthington
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
165
|
|
|
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.8.1 or,
|
166
|
|
|
|
|
|
|
at your option, any later version of Perl 5 you may have available.
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=cut
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# ########################################################################################
|
172
|
|
|
|
|
|
|
# Private Methods
|
173
|
|
|
|
|
|
|
# ########################################################################################
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# Differentiate Tree explores the current expression tree, recursively differentiating
|
176
|
|
|
|
|
|
|
# the branches of the tree.
|
177
|
|
|
|
|
|
|
# ########################################################################################
|
178
|
|
|
|
|
|
|
sub differentiateTree {
|
179
|
|
|
|
|
|
|
# Get invocant, variable and tree.
|
180
|
|
|
|
|
|
|
my ($self, $variable, $tree) = @_;
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# Generate traceback.
|
183
|
|
|
|
|
|
|
$self->{'traceback'} .= "Parsing " . $self->prettyPrint($tree) . "\n";
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# If we're at a node...
|
186
|
|
|
|
|
|
|
unless (ref $tree) {
|
187
|
|
|
|
|
|
|
# Is it the variable?
|
188
|
|
|
|
|
|
|
if ($tree eq $variable) {
|
189
|
|
|
|
|
|
|
# It goes to 1.
|
190
|
|
|
|
|
|
|
return 1;
|
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# Or - the variable...
|
193
|
|
|
|
|
|
|
} elsif ($tree eq "-$variable") {
|
194
|
|
|
|
|
|
|
# It goes to -1.
|
195
|
|
|
|
|
|
|
return -1;
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# Otherwise, it's a constant and goes to zero.
|
198
|
|
|
|
|
|
|
} else {
|
199
|
|
|
|
|
|
|
return 0;
|
200
|
|
|
|
|
|
|
}
|
201
|
|
|
|
|
|
|
} else {
|
202
|
|
|
|
|
|
|
# We've got a complex expression. Our actions from here depend on what the
|
203
|
|
|
|
|
|
|
# expression is.
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Addition or subtraction - just differentiate each operand.
|
206
|
|
|
|
|
|
|
if ($tree->{'operation'} eq '+' || $tree->{'operation'} eq '-') {
|
207
|
|
|
|
|
|
|
return {
|
208
|
|
|
|
|
|
|
operation => $tree->{'operation'},
|
209
|
|
|
|
|
|
|
operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
|
210
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand2'})
|
211
|
|
|
|
|
|
|
};
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
# Multiplication.
|
214
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} eq '*') {
|
215
|
|
|
|
|
|
|
# Check if any branches are constant.
|
216
|
|
|
|
|
|
|
my $o1c = $self->isConstant($variable, $tree->{'operand1'});
|
217
|
|
|
|
|
|
|
my $o2c = $self->isConstant($variable, $tree->{'operand2'});
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# If they're both constant, return the tree as it is.
|
220
|
|
|
|
|
|
|
if ($o1c && $o2c) {
|
221
|
|
|
|
|
|
|
return $tree;
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# If the first is constant, only differentiate the second.
|
224
|
|
|
|
|
|
|
} elsif ($o1c) {
|
225
|
|
|
|
|
|
|
return {
|
226
|
|
|
|
|
|
|
operation => $tree->{'operation'},
|
227
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
228
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand2'})
|
229
|
|
|
|
|
|
|
};
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# If the second is constant, only differentiate the first.
|
232
|
|
|
|
|
|
|
} elsif ($o2c) {
|
233
|
|
|
|
|
|
|
return {
|
234
|
|
|
|
|
|
|
operation => $tree->{'operation'},
|
235
|
|
|
|
|
|
|
operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
|
236
|
|
|
|
|
|
|
operand2 => $tree->{'operand2'}
|
237
|
|
|
|
|
|
|
};
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# Otherwise, it's the product rule. d[uv] = udv + vdu
|
240
|
|
|
|
|
|
|
} else {
|
241
|
|
|
|
|
|
|
return {
|
242
|
|
|
|
|
|
|
operation => '+',
|
243
|
|
|
|
|
|
|
operand1 =>
|
244
|
|
|
|
|
|
|
{
|
245
|
|
|
|
|
|
|
operation => '*',
|
246
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
247
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand2'})
|
248
|
|
|
|
|
|
|
},
|
249
|
|
|
|
|
|
|
operand2 =>
|
250
|
|
|
|
|
|
|
{
|
251
|
|
|
|
|
|
|
operation => '*',
|
252
|
|
|
|
|
|
|
operand1 => $tree->{'operand2'},
|
253
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
254
|
|
|
|
|
|
|
}
|
255
|
|
|
|
|
|
|
};
|
256
|
|
|
|
|
|
|
}
|
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Division.
|
259
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} eq '/') {
|
260
|
|
|
|
|
|
|
# Check if any branches are constant.
|
261
|
|
|
|
|
|
|
my $o1c = $self->isConstant($variable, $tree->{'operand1'});
|
262
|
|
|
|
|
|
|
my $o2c = $self->isConstant($variable, $tree->{'operand2'});
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# If they're both constant, return the tree as it is.
|
265
|
|
|
|
|
|
|
if ($o1c && $o2c) {
|
266
|
|
|
|
|
|
|
return $tree;
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# If the denominator is constant, just differentiate the top.
|
269
|
|
|
|
|
|
|
} elsif ($o2c) {
|
270
|
|
|
|
|
|
|
return {
|
271
|
|
|
|
|
|
|
operation => '/',
|
272
|
|
|
|
|
|
|
operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
|
273
|
|
|
|
|
|
|
operand2 => $tree->{'operand2'}
|
274
|
|
|
|
|
|
|
};
|
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# If the numerator is constant, e.g. k/u, then return k * d[u^-1].
|
277
|
|
|
|
|
|
|
} elsif ($o1c) {
|
278
|
|
|
|
|
|
|
my $uinv = {
|
279
|
|
|
|
|
|
|
operation => '^',
|
280
|
|
|
|
|
|
|
operand1 => $tree->{'operand2'},
|
281
|
|
|
|
|
|
|
operand2 => -1
|
282
|
|
|
|
|
|
|
};
|
283
|
|
|
|
|
|
|
return {
|
284
|
|
|
|
|
|
|
operation => '*',
|
285
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
286
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $uinv)
|
287
|
|
|
|
|
|
|
}
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# Otherwise, neither is constant. Use d[u/v] = (vdu - udv) / v^2.
|
290
|
|
|
|
|
|
|
} else {
|
291
|
|
|
|
|
|
|
my $vdu = {
|
292
|
|
|
|
|
|
|
operation => '*',
|
293
|
|
|
|
|
|
|
operand2 => $tree->{'operand2'},
|
294
|
|
|
|
|
|
|
operand1 => $self->differentiateTree($variable, $tree->{'operand1'})
|
295
|
|
|
|
|
|
|
};
|
296
|
|
|
|
|
|
|
my $udv = {
|
297
|
|
|
|
|
|
|
operation => '*',
|
298
|
|
|
|
|
|
|
operand2 => $tree->{'operand1'},
|
299
|
|
|
|
|
|
|
operand1 => $self->differentiateTree($variable, $tree->{'operand2'})
|
300
|
|
|
|
|
|
|
};
|
301
|
|
|
|
|
|
|
return {
|
302
|
|
|
|
|
|
|
operation => '/',
|
303
|
|
|
|
|
|
|
operand1 =>
|
304
|
|
|
|
|
|
|
{
|
305
|
|
|
|
|
|
|
operation => '-',
|
306
|
|
|
|
|
|
|
operand1 => $vdu,
|
307
|
|
|
|
|
|
|
operand2 => $udv
|
308
|
|
|
|
|
|
|
},
|
309
|
|
|
|
|
|
|
operand2 =>
|
310
|
|
|
|
|
|
|
{
|
311
|
|
|
|
|
|
|
operation => '^',
|
312
|
|
|
|
|
|
|
operand1 => $tree->{'operand2'},
|
313
|
|
|
|
|
|
|
operand2 => 2
|
314
|
|
|
|
|
|
|
}
|
315
|
|
|
|
|
|
|
};
|
316
|
|
|
|
|
|
|
}
|
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# Powers.
|
320
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} eq '^') {
|
321
|
|
|
|
|
|
|
# Check if any branches are constant.
|
322
|
|
|
|
|
|
|
my $o1c = $self->isConstant($variable, $tree->{'operand1'});
|
323
|
|
|
|
|
|
|
my $o2c = $self->isConstant($variable, $tree->{'operand2'});
|
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# If they're both constant, return the tree as it is.
|
326
|
|
|
|
|
|
|
if ($o1c && $o2c) {
|
327
|
|
|
|
|
|
|
return $tree;
|
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# If the power is constant...
|
330
|
|
|
|
|
|
|
} elsif ($o2c) {
|
331
|
|
|
|
|
|
|
# d[(f(x))^n] = n*f'(x)*f(x)^(n-1)
|
332
|
|
|
|
|
|
|
return {
|
333
|
|
|
|
|
|
|
operation => '*',
|
334
|
|
|
|
|
|
|
operand1 => $tree->{'operand2'},
|
335
|
|
|
|
|
|
|
operand2 =>
|
336
|
|
|
|
|
|
|
{
|
337
|
|
|
|
|
|
|
operation => '*',
|
338
|
|
|
|
|
|
|
operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
|
339
|
|
|
|
|
|
|
operand2 =>
|
340
|
|
|
|
|
|
|
{
|
341
|
|
|
|
|
|
|
operation => '^',
|
342
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
343
|
|
|
|
|
|
|
operand2 =>
|
344
|
|
|
|
|
|
|
{
|
345
|
|
|
|
|
|
|
operation => '-',
|
346
|
|
|
|
|
|
|
operand1 => $tree->{'operand2'},
|
347
|
|
|
|
|
|
|
operand2 => 1
|
348
|
|
|
|
|
|
|
}
|
349
|
|
|
|
|
|
|
}
|
350
|
|
|
|
|
|
|
}
|
351
|
|
|
|
|
|
|
};
|
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# If the value being raised to a power is constant...
|
354
|
|
|
|
|
|
|
} elsif ($o1c) {
|
355
|
|
|
|
|
|
|
# d[k^v] = dv * ln(k) * exp(ln(k) * v)
|
356
|
|
|
|
|
|
|
my $dv = $self->differentiateTree($variable, $tree->{'operand2'});
|
357
|
|
|
|
|
|
|
my $lnk = {
|
358
|
|
|
|
|
|
|
operation => 'ln',
|
359
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
360
|
|
|
|
|
|
|
operand2 => undef
|
361
|
|
|
|
|
|
|
};
|
362
|
|
|
|
|
|
|
return {
|
363
|
|
|
|
|
|
|
operation => '*',
|
364
|
|
|
|
|
|
|
operand1 => $dv,
|
365
|
|
|
|
|
|
|
operand2 =>
|
366
|
|
|
|
|
|
|
{
|
367
|
|
|
|
|
|
|
operation => '*',
|
368
|
|
|
|
|
|
|
operand1 => $lnk,
|
369
|
|
|
|
|
|
|
operand2 =>
|
370
|
|
|
|
|
|
|
{
|
371
|
|
|
|
|
|
|
operation => 'exp',
|
372
|
|
|
|
|
|
|
operand1 =>
|
373
|
|
|
|
|
|
|
{
|
374
|
|
|
|
|
|
|
operation => '*',
|
375
|
|
|
|
|
|
|
operand1 => $lnk,
|
376
|
|
|
|
|
|
|
operand2 => $tree->{'operand2'}
|
377
|
|
|
|
|
|
|
},
|
378
|
|
|
|
|
|
|
operand2 => undef
|
379
|
|
|
|
|
|
|
}
|
380
|
|
|
|
|
|
|
}
|
381
|
|
|
|
|
|
|
};
|
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# If it's a function of the variable raised to another function of the variable...
|
385
|
|
|
|
|
|
|
} else {
|
386
|
|
|
|
|
|
|
# d[u^v] = exp(ln(u) * v) * ((vdu)/u + ln(u)dv)
|
387
|
|
|
|
|
|
|
my $lnu = {
|
388
|
|
|
|
|
|
|
operation => 'ln',
|
389
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
390
|
|
|
|
|
|
|
operand2 => undef
|
391
|
|
|
|
|
|
|
};
|
392
|
|
|
|
|
|
|
my $dv = $self->differentiateTree($variable, $tree->{'operand2'});
|
393
|
|
|
|
|
|
|
my $vdu = {
|
394
|
|
|
|
|
|
|
operation => '*',
|
395
|
|
|
|
|
|
|
operand1 => $tree->{'operand2'},
|
396
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
397
|
|
|
|
|
|
|
};
|
398
|
|
|
|
|
|
|
return {
|
399
|
|
|
|
|
|
|
operation => '*',
|
400
|
|
|
|
|
|
|
operand1 =>
|
401
|
|
|
|
|
|
|
{
|
402
|
|
|
|
|
|
|
operation => 'exp',
|
403
|
|
|
|
|
|
|
operand1 =>
|
404
|
|
|
|
|
|
|
{
|
405
|
|
|
|
|
|
|
operation => '*',
|
406
|
|
|
|
|
|
|
operand1 => $lnu,
|
407
|
|
|
|
|
|
|
operand2 => $tree->{'operand2'}
|
408
|
|
|
|
|
|
|
},
|
409
|
|
|
|
|
|
|
operand2 => undef
|
410
|
|
|
|
|
|
|
},
|
411
|
|
|
|
|
|
|
operand2 =>
|
412
|
|
|
|
|
|
|
{
|
413
|
|
|
|
|
|
|
operation => '+',
|
414
|
|
|
|
|
|
|
operand1 =>
|
415
|
|
|
|
|
|
|
{
|
416
|
|
|
|
|
|
|
operation => '/',
|
417
|
|
|
|
|
|
|
operand1 => $vdu,
|
418
|
|
|
|
|
|
|
operand2 => $tree->{'operand1'}
|
419
|
|
|
|
|
|
|
},
|
420
|
|
|
|
|
|
|
operand2 =>
|
421
|
|
|
|
|
|
|
{
|
422
|
|
|
|
|
|
|
operation => '*',
|
423
|
|
|
|
|
|
|
operand1 => $lnu,
|
424
|
|
|
|
|
|
|
operand2 => $dv
|
425
|
|
|
|
|
|
|
}
|
426
|
|
|
|
|
|
|
}
|
427
|
|
|
|
|
|
|
};
|
428
|
|
|
|
|
|
|
}
|
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# Natural logarithm
|
431
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)ln$/) {
|
432
|
|
|
|
|
|
|
# Stash negativity.
|
433
|
|
|
|
|
|
|
my $neg = $1;
|
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# d[ln(u)] = du/u
|
436
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
437
|
|
|
|
|
|
|
return {
|
438
|
|
|
|
|
|
|
operation => '*',
|
439
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
440
|
|
|
|
|
|
|
operand2 =>
|
441
|
|
|
|
|
|
|
{
|
442
|
|
|
|
|
|
|
operation => '/',
|
443
|
|
|
|
|
|
|
operand1 => $du,
|
444
|
|
|
|
|
|
|
operand2 => $tree->{'operand1'}
|
445
|
|
|
|
|
|
|
}
|
446
|
|
|
|
|
|
|
};
|
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# Exponential (e)
|
449
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)exp$/) {
|
450
|
|
|
|
|
|
|
# Stash negativity.
|
451
|
|
|
|
|
|
|
my $neg = $1;
|
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# d[exp(u)] = exp(u)du
|
454
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
455
|
|
|
|
|
|
|
return {
|
456
|
|
|
|
|
|
|
operation => '*',
|
457
|
|
|
|
|
|
|
operand1 => $du,
|
458
|
|
|
|
|
|
|
operand2 => $tree
|
459
|
|
|
|
|
|
|
};
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# sin
|
462
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)sin$/) {
|
463
|
|
|
|
|
|
|
# Stash negativity.
|
464
|
|
|
|
|
|
|
my $neg = $1;
|
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# d[sin(u)] = cos(u)du
|
467
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
468
|
|
|
|
|
|
|
return {
|
469
|
|
|
|
|
|
|
operation => '*',
|
470
|
|
|
|
|
|
|
operand1 => $du,
|
471
|
|
|
|
|
|
|
operand2 =>
|
472
|
|
|
|
|
|
|
{
|
473
|
|
|
|
|
|
|
operation => "${neg}cos",
|
474
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
475
|
|
|
|
|
|
|
operand2 => undef
|
476
|
|
|
|
|
|
|
}
|
477
|
|
|
|
|
|
|
};
|
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
# cos
|
480
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)cos$/) {
|
481
|
|
|
|
|
|
|
# Stash negativity.
|
482
|
|
|
|
|
|
|
my $neg = $1 eq '-' ? '' : '-';
|
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# d[cos(u)] = -sin(u)du
|
485
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
486
|
|
|
|
|
|
|
return {
|
487
|
|
|
|
|
|
|
operation => '*',
|
488
|
|
|
|
|
|
|
operand1 => $du,
|
489
|
|
|
|
|
|
|
operand2 =>
|
490
|
|
|
|
|
|
|
{
|
491
|
|
|
|
|
|
|
operation => "${neg}sin",
|
492
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
493
|
|
|
|
|
|
|
operand2 => undef
|
494
|
|
|
|
|
|
|
}
|
495
|
|
|
|
|
|
|
};
|
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# tan
|
498
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)tan$/) {
|
499
|
|
|
|
|
|
|
# Stash negativity.
|
500
|
|
|
|
|
|
|
my $neg = $1;
|
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
# d[tan(u)] = (sec(u))^2 * du
|
503
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
504
|
|
|
|
|
|
|
return {
|
505
|
|
|
|
|
|
|
operation => '*',
|
506
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
507
|
|
|
|
|
|
|
operand2 =>
|
508
|
|
|
|
|
|
|
{
|
509
|
|
|
|
|
|
|
operation => '*',
|
510
|
|
|
|
|
|
|
operand1 => $du,
|
511
|
|
|
|
|
|
|
operand2 =>
|
512
|
|
|
|
|
|
|
{
|
513
|
|
|
|
|
|
|
operation => '^',
|
514
|
|
|
|
|
|
|
operand1 =>
|
515
|
|
|
|
|
|
|
{
|
516
|
|
|
|
|
|
|
operation => "sec",
|
517
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
518
|
|
|
|
|
|
|
operand2 => undef
|
519
|
|
|
|
|
|
|
},
|
520
|
|
|
|
|
|
|
operand2 => 2
|
521
|
|
|
|
|
|
|
}
|
522
|
|
|
|
|
|
|
}
|
523
|
|
|
|
|
|
|
};
|
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# sec
|
526
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)sec$/) {
|
527
|
|
|
|
|
|
|
# Stash negativity.
|
528
|
|
|
|
|
|
|
my $neg = $1;
|
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
# Convert to 1/cos and differentiate.
|
531
|
|
|
|
|
|
|
return $self->differentiateTree($variable, {
|
532
|
|
|
|
|
|
|
operation => '/',
|
533
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
534
|
|
|
|
|
|
|
operand2 =>
|
535
|
|
|
|
|
|
|
{
|
536
|
|
|
|
|
|
|
operation => 'cos',
|
537
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
538
|
|
|
|
|
|
|
operand2 => undef
|
539
|
|
|
|
|
|
|
}
|
540
|
|
|
|
|
|
|
});
|
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
# cosec
|
543
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)cosec$/) {
|
544
|
|
|
|
|
|
|
# Stash negativity.
|
545
|
|
|
|
|
|
|
my $neg = $1;
|
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
# Convert to 1/sin and differentiate.
|
548
|
|
|
|
|
|
|
return $self->differentiateTree($variable, {
|
549
|
|
|
|
|
|
|
operation => '/',
|
550
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
551
|
|
|
|
|
|
|
operand2 =>
|
552
|
|
|
|
|
|
|
{
|
553
|
|
|
|
|
|
|
operation => 'sin',
|
554
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
555
|
|
|
|
|
|
|
operand2 => undef
|
556
|
|
|
|
|
|
|
}
|
557
|
|
|
|
|
|
|
});
|
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
# cot
|
560
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)cot$/) {
|
561
|
|
|
|
|
|
|
# Stash negativity.
|
562
|
|
|
|
|
|
|
my $neg = $1;
|
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# Convert to 1/tan and differentiate.
|
565
|
|
|
|
|
|
|
return $self->differentiateTree($variable, {
|
566
|
|
|
|
|
|
|
operation => '/',
|
567
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
568
|
|
|
|
|
|
|
operand2 =>
|
569
|
|
|
|
|
|
|
{
|
570
|
|
|
|
|
|
|
operation => 'tan',
|
571
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
572
|
|
|
|
|
|
|
operand2 => undef
|
573
|
|
|
|
|
|
|
}
|
574
|
|
|
|
|
|
|
});
|
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
# sinh
|
577
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)sinh$/) {
|
578
|
|
|
|
|
|
|
# Stash negativity.
|
579
|
|
|
|
|
|
|
my $neg = $1;
|
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
# d[sinh(u)] = cosh(u)du
|
582
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
583
|
|
|
|
|
|
|
return {
|
584
|
|
|
|
|
|
|
operation => '*',
|
585
|
|
|
|
|
|
|
operand1 => $du,
|
586
|
|
|
|
|
|
|
operand2 =>
|
587
|
|
|
|
|
|
|
{
|
588
|
|
|
|
|
|
|
operation => "${neg}cosh",
|
589
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
590
|
|
|
|
|
|
|
operand2 => undef
|
591
|
|
|
|
|
|
|
}
|
592
|
|
|
|
|
|
|
};
|
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
# cosh
|
595
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)cosh$/) {
|
596
|
|
|
|
|
|
|
# Stash negativity.
|
597
|
|
|
|
|
|
|
my $neg = $1;
|
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
# d[cosh(u)] = sinh(u)du
|
600
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
601
|
|
|
|
|
|
|
return {
|
602
|
|
|
|
|
|
|
operation => '*',
|
603
|
|
|
|
|
|
|
operand1 => $du,
|
604
|
|
|
|
|
|
|
operand2 =>
|
605
|
|
|
|
|
|
|
{
|
606
|
|
|
|
|
|
|
operation => "${neg}sinh",
|
607
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
608
|
|
|
|
|
|
|
operand2 => undef
|
609
|
|
|
|
|
|
|
}
|
610
|
|
|
|
|
|
|
};
|
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
# tanh
|
613
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)tanh$/) {
|
614
|
|
|
|
|
|
|
# Stash negativity.
|
615
|
|
|
|
|
|
|
my $neg = $1;
|
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
# d[tanh(u)] = (sech(u))^2 * du
|
618
|
|
|
|
|
|
|
my $du = $self->differentiateTree($variable, $tree->{'operand1'});
|
619
|
|
|
|
|
|
|
return {
|
620
|
|
|
|
|
|
|
operation => '*',
|
621
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
622
|
|
|
|
|
|
|
operand2 =>
|
623
|
|
|
|
|
|
|
{
|
624
|
|
|
|
|
|
|
operation => '*',
|
625
|
|
|
|
|
|
|
operand1 => $du,
|
626
|
|
|
|
|
|
|
operand2 =>
|
627
|
|
|
|
|
|
|
{
|
628
|
|
|
|
|
|
|
operation => '^',
|
629
|
|
|
|
|
|
|
operand1 =>
|
630
|
|
|
|
|
|
|
{
|
631
|
|
|
|
|
|
|
operation => "sech",
|
632
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
633
|
|
|
|
|
|
|
operand2 => undef
|
634
|
|
|
|
|
|
|
},
|
635
|
|
|
|
|
|
|
operand2 => 2
|
636
|
|
|
|
|
|
|
}
|
637
|
|
|
|
|
|
|
}
|
638
|
|
|
|
|
|
|
};
|
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
# sech
|
641
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)sech$/) {
|
642
|
|
|
|
|
|
|
# Stash negativity.
|
643
|
|
|
|
|
|
|
my $neg = $1;
|
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
# Convert to 1/cosh and differentiate.
|
646
|
|
|
|
|
|
|
return $self->differentiateTree($variable, {
|
647
|
|
|
|
|
|
|
operation => '/',
|
648
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
649
|
|
|
|
|
|
|
operand2 =>
|
650
|
|
|
|
|
|
|
{
|
651
|
|
|
|
|
|
|
operation => 'cosh',
|
652
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
653
|
|
|
|
|
|
|
operand2 => undef
|
654
|
|
|
|
|
|
|
}
|
655
|
|
|
|
|
|
|
});
|
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
# cosech
|
658
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)cosech$/) {
|
659
|
|
|
|
|
|
|
# Stash negativity.
|
660
|
|
|
|
|
|
|
my $neg = $1;
|
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# Convert to 1/sinh and differentiate.
|
663
|
|
|
|
|
|
|
return $self->differentiateTree($variable, {
|
664
|
|
|
|
|
|
|
operation => '/',
|
665
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
666
|
|
|
|
|
|
|
operand2 =>
|
667
|
|
|
|
|
|
|
{
|
668
|
|
|
|
|
|
|
operation => 'sinh',
|
669
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
670
|
|
|
|
|
|
|
operand2 => undef
|
671
|
|
|
|
|
|
|
}
|
672
|
|
|
|
|
|
|
});
|
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
# coth
|
675
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)coth$/) {
|
676
|
|
|
|
|
|
|
# Stash negativity.
|
677
|
|
|
|
|
|
|
my $neg = $1;
|
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
# Convert to 1/tanh and differentiate.
|
680
|
|
|
|
|
|
|
return $self->differentiateTree($variable, {
|
681
|
|
|
|
|
|
|
operation => '/',
|
682
|
|
|
|
|
|
|
operand1 => "${neg}1",
|
683
|
|
|
|
|
|
|
operand2 =>
|
684
|
|
|
|
|
|
|
{
|
685
|
|
|
|
|
|
|
operation => 'tanh',
|
686
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
687
|
|
|
|
|
|
|
operand2 => undef
|
688
|
|
|
|
|
|
|
}
|
689
|
|
|
|
|
|
|
});
|
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
# asin
|
692
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)asin$/) {
|
693
|
|
|
|
|
|
|
# Stash negativity.
|
694
|
|
|
|
|
|
|
my $neg = $1;
|
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
# d[asin(u)] = du / (1 - u^2)^0.5
|
697
|
|
|
|
|
|
|
my $du;
|
698
|
|
|
|
|
|
|
if ($neg) {
|
699
|
|
|
|
|
|
|
$du = {
|
700
|
|
|
|
|
|
|
operation => '-',
|
701
|
|
|
|
|
|
|
operand1 => '0',
|
702
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
703
|
|
|
|
|
|
|
};
|
704
|
|
|
|
|
|
|
} else {
|
705
|
|
|
|
|
|
|
$du = $self->differentiateTree($variable, $tree->{'operand1'});
|
706
|
|
|
|
|
|
|
}
|
707
|
|
|
|
|
|
|
return {
|
708
|
|
|
|
|
|
|
operation => '/',
|
709
|
|
|
|
|
|
|
operand1 => $du,
|
710
|
|
|
|
|
|
|
operand2 =>
|
711
|
|
|
|
|
|
|
{
|
712
|
|
|
|
|
|
|
operation => '^',
|
713
|
|
|
|
|
|
|
operand1 =>
|
714
|
|
|
|
|
|
|
{
|
715
|
|
|
|
|
|
|
operation => '-',
|
716
|
|
|
|
|
|
|
operand1 => 1,
|
717
|
|
|
|
|
|
|
operand2 =>
|
718
|
|
|
|
|
|
|
{
|
719
|
|
|
|
|
|
|
operation => '^',
|
720
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
721
|
|
|
|
|
|
|
operand2 => 2
|
722
|
|
|
|
|
|
|
}
|
723
|
|
|
|
|
|
|
},
|
724
|
|
|
|
|
|
|
operand2 => 0.5
|
725
|
|
|
|
|
|
|
}
|
726
|
|
|
|
|
|
|
};
|
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
# acos
|
729
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)acos$/) {
|
730
|
|
|
|
|
|
|
# Stash negativity.
|
731
|
|
|
|
|
|
|
my $neg = $1;
|
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
# d[acos(u)] = -du / (1 - u^2)^0.5
|
734
|
|
|
|
|
|
|
my $du;
|
735
|
|
|
|
|
|
|
if ($neg) {
|
736
|
|
|
|
|
|
|
$du = $self->differentiateTree($variable, $tree->{'operand1'});
|
737
|
|
|
|
|
|
|
} else {
|
738
|
|
|
|
|
|
|
$du = {
|
739
|
|
|
|
|
|
|
operation => '-',
|
740
|
|
|
|
|
|
|
operand1 => '0',
|
741
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
742
|
|
|
|
|
|
|
};
|
743
|
|
|
|
|
|
|
}
|
744
|
|
|
|
|
|
|
return {
|
745
|
|
|
|
|
|
|
operation => '/',
|
746
|
|
|
|
|
|
|
operand1 => $du,
|
747
|
|
|
|
|
|
|
operand2 =>
|
748
|
|
|
|
|
|
|
{
|
749
|
|
|
|
|
|
|
operation => '^',
|
750
|
|
|
|
|
|
|
operand1 =>
|
751
|
|
|
|
|
|
|
{
|
752
|
|
|
|
|
|
|
operation => '-',
|
753
|
|
|
|
|
|
|
operand1 => 1,
|
754
|
|
|
|
|
|
|
operand2 =>
|
755
|
|
|
|
|
|
|
{
|
756
|
|
|
|
|
|
|
operation => '^',
|
757
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
758
|
|
|
|
|
|
|
operand2 => 2
|
759
|
|
|
|
|
|
|
}
|
760
|
|
|
|
|
|
|
},
|
761
|
|
|
|
|
|
|
operand2 => 0.5
|
762
|
|
|
|
|
|
|
}
|
763
|
|
|
|
|
|
|
};
|
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
# atan
|
766
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)atan$/) {
|
767
|
|
|
|
|
|
|
# Stash negativity.
|
768
|
|
|
|
|
|
|
my $neg = $1;
|
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
# d[atan(u)] = du / (1 + u^2)
|
771
|
|
|
|
|
|
|
my $du;
|
772
|
|
|
|
|
|
|
if ($neg) {
|
773
|
|
|
|
|
|
|
$du = {
|
774
|
|
|
|
|
|
|
operation => '-',
|
775
|
|
|
|
|
|
|
operand1 => '0',
|
776
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
777
|
|
|
|
|
|
|
};
|
778
|
|
|
|
|
|
|
} else {
|
779
|
|
|
|
|
|
|
$du = $self->differentiateTree($variable, $tree->{'operand1'});
|
780
|
|
|
|
|
|
|
}
|
781
|
|
|
|
|
|
|
return {
|
782
|
|
|
|
|
|
|
operation => '/',
|
783
|
|
|
|
|
|
|
operand1 => $du,
|
784
|
|
|
|
|
|
|
operand2 =>
|
785
|
|
|
|
|
|
|
{
|
786
|
|
|
|
|
|
|
operation => '+',
|
787
|
|
|
|
|
|
|
operand1 => 1,
|
788
|
|
|
|
|
|
|
operand2 =>
|
789
|
|
|
|
|
|
|
{
|
790
|
|
|
|
|
|
|
operation => '^',
|
791
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
792
|
|
|
|
|
|
|
operand2 => 2
|
793
|
|
|
|
|
|
|
}
|
794
|
|
|
|
|
|
|
}
|
795
|
|
|
|
|
|
|
};
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
# asinh
|
798
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)asinh$/) {
|
799
|
|
|
|
|
|
|
# Stash negativity.
|
800
|
|
|
|
|
|
|
my $neg = $1;
|
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
# d[asinh(u)] = du / (1 + u^2)^0.5
|
803
|
|
|
|
|
|
|
my $du;
|
804
|
|
|
|
|
|
|
if ($neg) {
|
805
|
|
|
|
|
|
|
$du = {
|
806
|
|
|
|
|
|
|
operation => '-',
|
807
|
|
|
|
|
|
|
operand1 => '0',
|
808
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
809
|
|
|
|
|
|
|
};
|
810
|
|
|
|
|
|
|
} else {
|
811
|
|
|
|
|
|
|
$du = $self->differentiateTree($variable, $tree->{'operand1'});
|
812
|
|
|
|
|
|
|
}
|
813
|
|
|
|
|
|
|
return {
|
814
|
|
|
|
|
|
|
operation => '/',
|
815
|
|
|
|
|
|
|
operand1 => $du,
|
816
|
|
|
|
|
|
|
operand2 =>
|
817
|
|
|
|
|
|
|
{
|
818
|
|
|
|
|
|
|
operation => '^',
|
819
|
|
|
|
|
|
|
operand1 =>
|
820
|
|
|
|
|
|
|
{
|
821
|
|
|
|
|
|
|
operation => '+',
|
822
|
|
|
|
|
|
|
operand1 => 1,
|
823
|
|
|
|
|
|
|
operand2 =>
|
824
|
|
|
|
|
|
|
{
|
825
|
|
|
|
|
|
|
operation => '^',
|
826
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
827
|
|
|
|
|
|
|
operand2 => 2
|
828
|
|
|
|
|
|
|
}
|
829
|
|
|
|
|
|
|
},
|
830
|
|
|
|
|
|
|
operand2 => 0.5
|
831
|
|
|
|
|
|
|
}
|
832
|
|
|
|
|
|
|
};
|
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
# acosh
|
835
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)acosh$/) {
|
836
|
|
|
|
|
|
|
# Stash negativity.
|
837
|
|
|
|
|
|
|
my $neg = $1;
|
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
# d[acosh(u)] = du / (u^2 - 1)^0.5
|
840
|
|
|
|
|
|
|
my $du;
|
841
|
|
|
|
|
|
|
if ($neg) {
|
842
|
|
|
|
|
|
|
$du = {
|
843
|
|
|
|
|
|
|
operation => '-',
|
844
|
|
|
|
|
|
|
operand1 => '0',
|
845
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
846
|
|
|
|
|
|
|
};
|
847
|
|
|
|
|
|
|
} else {
|
848
|
|
|
|
|
|
|
$du = $self->differentiateTree($variable, $tree->{'operand1'});
|
849
|
|
|
|
|
|
|
}
|
850
|
|
|
|
|
|
|
return {
|
851
|
|
|
|
|
|
|
operation => '/',
|
852
|
|
|
|
|
|
|
operand1 => $du,
|
853
|
|
|
|
|
|
|
operand2 =>
|
854
|
|
|
|
|
|
|
{
|
855
|
|
|
|
|
|
|
operation => '^',
|
856
|
|
|
|
|
|
|
operand1 =>
|
857
|
|
|
|
|
|
|
{
|
858
|
|
|
|
|
|
|
operation => '-',
|
859
|
|
|
|
|
|
|
operand1 =>
|
860
|
|
|
|
|
|
|
{
|
861
|
|
|
|
|
|
|
operation => '^',
|
862
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
863
|
|
|
|
|
|
|
operand2 => 2
|
864
|
|
|
|
|
|
|
},
|
865
|
|
|
|
|
|
|
operand2 => 1
|
866
|
|
|
|
|
|
|
},
|
867
|
|
|
|
|
|
|
operand2 => 0.5
|
868
|
|
|
|
|
|
|
}
|
869
|
|
|
|
|
|
|
};
|
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
# atanh
|
872
|
|
|
|
|
|
|
} elsif ($tree->{'operation'} =~ /^(\-?)atanh$/) {
|
873
|
|
|
|
|
|
|
# Stash negativity.
|
874
|
|
|
|
|
|
|
my $neg = $1;
|
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
# d[atanh(u)] = du / (1 - u^2)
|
877
|
|
|
|
|
|
|
my $du;
|
878
|
|
|
|
|
|
|
if ($neg) {
|
879
|
|
|
|
|
|
|
$du = {
|
880
|
|
|
|
|
|
|
operation => '-',
|
881
|
|
|
|
|
|
|
operand1 => '0',
|
882
|
|
|
|
|
|
|
operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
|
883
|
|
|
|
|
|
|
};
|
884
|
|
|
|
|
|
|
} else {
|
885
|
|
|
|
|
|
|
$du = $self->differentiateTree($variable, $tree->{'operand1'});
|
886
|
|
|
|
|
|
|
}
|
887
|
|
|
|
|
|
|
return {
|
888
|
|
|
|
|
|
|
operation => '/',
|
889
|
|
|
|
|
|
|
operand1 => $du,
|
890
|
|
|
|
|
|
|
operand2 =>
|
891
|
|
|
|
|
|
|
{
|
892
|
|
|
|
|
|
|
operation => '-',
|
893
|
|
|
|
|
|
|
operand1 => 1,
|
894
|
|
|
|
|
|
|
operand2 =>
|
895
|
|
|
|
|
|
|
{
|
896
|
|
|
|
|
|
|
operation => '^',
|
897
|
|
|
|
|
|
|
operand1 => $tree->{'operand1'},
|
898
|
|
|
|
|
|
|
operand2 => 2
|
899
|
|
|
|
|
|
|
}
|
900
|
|
|
|
|
|
|
}
|
901
|
|
|
|
|
|
|
};
|
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
# Otherwise, we don't know what it is.
|
904
|
|
|
|
|
|
|
} else {
|
905
|
|
|
|
|
|
|
$self->{'error'} = "Could not differentiate " . $self->prettyPrint($tree);
|
906
|
|
|
|
|
|
|
die;
|
907
|
|
|
|
|
|
|
}
|
908
|
|
|
|
|
|
|
}
|
909
|
|
|
|
|
|
|
}
|
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
1;
|
912
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
|