File Coverage

blib/lib/Math/Calculus/Differentiate.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


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