r20086 - in /branches/upstream/libmath-calculus-differentiate-perl: ./ current/ current/Changes current/Differentiate.pm current/MANIFEST current/META.yml current/Makefile.PL current/README current/test.pl
deepak-guest at users.alioth.debian.org
deepak-guest at users.alioth.debian.org
Sun May 18 14:56:16 UTC 2008
Author: deepak-guest
Date: Sun May 18 14:56:16 2008
New Revision: 20086
URL: http://svn.debian.org/wsvn/?sc=1&rev=20086
Log:
[svn-inject] Installing original source of libmath-calculus-differentiate-perl
Added:
branches/upstream/libmath-calculus-differentiate-perl/
branches/upstream/libmath-calculus-differentiate-perl/current/
branches/upstream/libmath-calculus-differentiate-perl/current/Changes
branches/upstream/libmath-calculus-differentiate-perl/current/Differentiate.pm
branches/upstream/libmath-calculus-differentiate-perl/current/MANIFEST
branches/upstream/libmath-calculus-differentiate-perl/current/META.yml
branches/upstream/libmath-calculus-differentiate-perl/current/Makefile.PL
branches/upstream/libmath-calculus-differentiate-perl/current/README
branches/upstream/libmath-calculus-differentiate-perl/current/test.pl
Added: branches/upstream/libmath-calculus-differentiate-perl/current/Changes
URL: http://svn.debian.org/wsvn/branches/upstream/libmath-calculus-differentiate-perl/current/Changes?rev=20086&op=file
==============================================================================
--- branches/upstream/libmath-calculus-differentiate-perl/current/Changes (added)
+++ branches/upstream/libmath-calculus-differentiate-perl/current/Changes Sun May 18 14:56:16 2008
@@ -1,0 +1,28 @@
+Revision history for Perl module Math::Calculus::Differentiate
+==============================================================
+VERSION 0.3
+* Released to CPAN 5th January 2004
+* Abstracted much code out to Math::Calculus::Expression,
+ which this module now inherits.
+* Fixed an expression parser bug.
+
+VERSION 0.2.1
+* Released to CPAN on 4th September 2004.
+* Fixed several bugs relating to handling of negation.
+* Added support for differentiating inverse trigometric and
+ hyperbolic functions (asin, acos, atan, asinh, acosh and
+ atanh).
+* Introduced several more rules to the simplifier.
+* Included a handful of regression tests.
+
+VERSION 0.2
+* Released to CPAN on 1st September 2004.
+* Completely re-written to use a tree structure internally.
+* Precedence problems gone, and the / operator works.
+* Interface changed from that of the 0.1 module.
+* Documentation written. I didn't write any for 0.1, just in
+ case somebody tried to use it. ;-)
+
+VERSION 0.1
+* Released informally, badly written, never made it to CPAN,
+ eventually scrapped completely.
Added: branches/upstream/libmath-calculus-differentiate-perl/current/Differentiate.pm
URL: http://svn.debian.org/wsvn/branches/upstream/libmath-calculus-differentiate-perl/current/Differentiate.pm?rev=20086&op=file
==============================================================================
--- branches/upstream/libmath-calculus-differentiate-perl/current/Differentiate.pm (added)
+++ branches/upstream/libmath-calculus-differentiate-perl/current/Differentiate.pm Sun May 18 14:56:16 2008
@@ -1,0 +1,914 @@
+# ########################################################################################
+# A CALCULUS DIFFERENTIATION OBJECT
+# An implementation of algebraic differentiation by Jonathan Worthington.
+# Copyright (C) Jonathan Worthington 2004
+# This module may be used and distributed under the same terms as Perl.
+# ########################################################################################
+
+package Math::Calculus::Differentiate;
+use 5.006;
+use Math::Calculus::Expression;
+use strict;
+our $VERSION = '0.3';
+our @ISA = qw/Math::Calculus::Expression/;
+
+=head1 NAME
+
+Math::Calculus::Differentiate - Algebraic Differentiation Engine
+
+=head1 SYNOPSIS
+
+ use Math::Calculus::Differentiate;
+
+ # Create an object.
+ my $exp = Math::Calculus::Differentiate->new;
+
+ # Set a variable and expression.
+ $exp->addVariable('x');
+ $exp->setExpression('x^2 + 5*x') or die $exp->getError;
+
+ # Differentiate and simplify.
+ $exp->differentiate or die $exp->getError;;
+ $exp->simplify or die $exp->getError;;
+
+ # Print the result.
+ print $exp->getExpression; # Prints 2*x + 5
+
+
+=head1 DESCRIPTION
+
+This module can take an algebraic expression, parse it into a tree structure, modify
+the tree to give a representation of the differentiated function, simplify the tree
+and turn the tree back into an output of the same form as the input.
+
+It supports differentiation of expressions including the +, -, *, / and ^ (raise to
+power) operators, bracketed expressions to enable correct precedence and the functions
+ln, exp, sin, cos, tan, sec, cosec, cot, sinh, cosh, tanh, sech, cosech, coth, asin,
+acos, atan, asinh, acosh and atanh.
+
+=head1 EXPORT
+
+None by default.
+
+=head1 METHODS
+
+=item new
+
+ $exp = Math::Calculus::Differentiate->new;
+
+Creates a new instance of the differentiation engine, which can hold an individual
+expression.
+
+=item addVariable
+
+ $exp->addVariable('x');
+
+Sets a certain named value in the expression as being a variable. A named value must be
+an alphabetic chracter.
+
+=item setExpression
+
+ $exp->setExpression('x^2 + 5*x);
+
+Takes an expression in human-readable form and stores it internally as a tree structure,
+checking it is a valid expression that the module can understand in the process. Note that
+the engine is strict about syntax. For example, note above that you must write 5*x and not
+just 5x. Whitespace is allowed in the expression, but does not have any effect on precedence.
+If you require control of precedence, use brackets; bracketed expressions will always be
+evaluated first, as you would normally expect. The module follows the BODMAS precedence
+convention. Returns undef on failure and a true value on success.
+
+=item getExpression
+
+ $expr = $exp->getExpression;
+
+Returns a textaul, human readable representation of the expression that is being stored.
+
+=cut
+
+
+# Differentiate.
+# ##############
+
+=item differentiate
+
+ $exp->differentiate('x');
+
+Differentiates the expression that was stored with setExpression with respect to the variable
+passed as a parameter. Returns undef on failure and a true value on success.
+
+=cut
+
+sub differentiate {
+ # Get invocant and variable.
+ my ($self, $variable) = @_;
+
+ # Check variable is in the list of variables.
+ return undef unless grep { $_ eq $variable } @{$self->{'variables'}};
+
+ # Clear error and traceback, and pass control to the differentiate routine.
+ $self->{'error'} = $self->{'traceback'} = undef;
+ eval {
+ $self->{'expression'} = $self->differentiateTree($variable, $self->{'expression'});
+ };
+
+ # Return an appropriate value (or lack thereof...).
+ if ($self->{'error'}) {
+ return undef;
+ } else {
+ return 1;
+ }
+}
+
+
+=item simplify
+
+ $exp->simplify;
+
+Attempts to simplify the expression that is stored internally. It is a very good idea to call
+this after calling differentiate, as the tree will often not be in the most compact possible
+form, and this will affect the readability of output from getExpression and the performance
+of future calls to differentiate if you are intending to obtain higher derivatives. Returns
+undef on failure and a true value on success.
+
+=item getTraceback
+
+ $exp->getTraceback;
+
+When setExpression and differentiate are called, a traceback is generated to describe
+what these functions did. If an error occurs, this traceback can be extremely useful
+in helping track down the source of the error.
+
+=item getError
+
+ $exp->getError;
+
+When any method other than getTraceback is called, the error message stored is cleared, and
+then any errors that occur during the execution of the method are stored. If failure occurs,
+call this method to get a textual representation of the error.
+
+=head1 SEE ALSO
+
+The author of this module has a website at L<http://www.jwcs.net/~jonathan/>, which has
+the latest news about the module and a web-based frontend to allow you to test the module
+out for yourself.
+
+=head1 AUTHOR
+
+Jonathan Worthington, E<lt>jonathan at jwcs.netE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2004 by Jonathan Worthington
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+=cut
+
+
+# ########################################################################################
+# Private Methods
+# ########################################################################################
+
+# Differentiate Tree explores the current expression tree, recursively differentiating
+# the branches of the tree.
+# ########################################################################################
+sub differentiateTree {
+ # Get invocant, variable and tree.
+ my ($self, $variable, $tree) = @_;
+
+ # Generate traceback.
+ $self->{'traceback'} .= "Parsing " . $self->prettyPrint($tree) . "\n";
+
+ # If we're at a node...
+ unless (ref $tree) {
+ # Is it the variable?
+ if ($tree eq $variable) {
+ # It goes to 1.
+ return 1;
+
+ # Or - the variable...
+ } elsif ($tree eq "-$variable") {
+ # It goes to -1.
+ return -1;
+
+ # Otherwise, it's a constant and goes to zero.
+ } else {
+ return 0;
+ }
+ } else {
+ # We've got a complex expression. Our actions from here depend on what the
+ # expression is.
+
+ # Addition or subtraction - just differentiate each operand.
+ if ($tree->{'operation'} eq '+' || $tree->{'operation'} eq '-') {
+ return {
+ operation => $tree->{'operation'},
+ operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
+ operand2 => $self->differentiateTree($variable, $tree->{'operand2'})
+ };
+
+ # Multiplication.
+ } elsif ($tree->{'operation'} eq '*') {
+ # Check if any branches are constant.
+ my $o1c = $self->isConstant($variable, $tree->{'operand1'});
+ my $o2c = $self->isConstant($variable, $tree->{'operand2'});
+
+ # If they're both constant, return the tree as it is.
+ if ($o1c && $o2c) {
+ return $tree;
+
+ # If the first is constant, only differentiate the second.
+ } elsif ($o1c) {
+ return {
+ operation => $tree->{'operation'},
+ operand1 => $tree->{'operand1'},
+ operand2 => $self->differentiateTree($variable, $tree->{'operand2'})
+ };
+
+ # If the second is constant, only differentiate the first.
+ } elsif ($o2c) {
+ return {
+ operation => $tree->{'operation'},
+ operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
+ operand2 => $tree->{'operand2'}
+ };
+
+ # Otherwise, it's the product rule. d[uv] = udv + vdu
+ } else {
+ return {
+ operation => '+',
+ operand1 =>
+ {
+ operation => '*',
+ operand1 => $tree->{'operand1'},
+ operand2 => $self->differentiateTree($variable, $tree->{'operand2'})
+ },
+ operand2 =>
+ {
+ operation => '*',
+ operand1 => $tree->{'operand2'},
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ }
+ };
+ }
+
+ # Division.
+ } elsif ($tree->{'operation'} eq '/') {
+ # Check if any branches are constant.
+ my $o1c = $self->isConstant($variable, $tree->{'operand1'});
+ my $o2c = $self->isConstant($variable, $tree->{'operand2'});
+
+ # If they're both constant, return the tree as it is.
+ if ($o1c && $o2c) {
+ return $tree;
+
+ # If the denominator is constant, just differentiate the top.
+ } elsif ($o2c) {
+ return {
+ operation => '/',
+ operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
+ operand2 => $tree->{'operand2'}
+ };
+
+ # If the numerator is constant, e.g. k/u, then return k * d[u^-1].
+ } elsif ($o1c) {
+ my $uinv = {
+ operation => '^',
+ operand1 => $tree->{'operand2'},
+ operand2 => -1
+ };
+ return {
+ operation => '*',
+ operand1 => $tree->{'operand1'},
+ operand2 => $self->differentiateTree($variable, $uinv)
+ }
+
+ # Otherwise, neither is constant. Use d[u/v] = (vdu - udv) / v^2.
+ } else {
+ my $vdu = {
+ operation => '*',
+ operand2 => $tree->{'operand2'},
+ operand1 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ my $udv = {
+ operation => '*',
+ operand2 => $tree->{'operand1'},
+ operand1 => $self->differentiateTree($variable, $tree->{'operand2'})
+ };
+ return {
+ operation => '/',
+ operand1 =>
+ {
+ operation => '-',
+ operand1 => $vdu,
+ operand2 => $udv
+ },
+ operand2 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand2'},
+ operand2 => 2
+ }
+ };
+ }
+
+
+ # Powers.
+ } elsif ($tree->{'operation'} eq '^') {
+ # Check if any branches are constant.
+ my $o1c = $self->isConstant($variable, $tree->{'operand1'});
+ my $o2c = $self->isConstant($variable, $tree->{'operand2'});
+
+ # If they're both constant, return the tree as it is.
+ if ($o1c && $o2c) {
+ return $tree;
+
+ # If the power is constant...
+ } elsif ($o2c) {
+ # d[(f(x))^n] = n*f'(x)*f(x)^(n-1)
+ return {
+ operation => '*',
+ operand1 => $tree->{'operand2'},
+ operand2 =>
+ {
+ operation => '*',
+ operand1 => $self->differentiateTree($variable, $tree->{'operand1'}),
+ operand2 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand1'},
+ operand2 =>
+ {
+ operation => '-',
+ operand1 => $tree->{'operand2'},
+ operand2 => 1
+ }
+ }
+ }
+ };
+
+ # If the value being raised to a power is constant...
+ } elsif ($o1c) {
+ # d[k^v] = dv * ln(k) * exp(ln(k) * v)
+ my $dv = $self->differentiateTree($variable, $tree->{'operand2'});
+ my $lnk = {
+ operation => 'ln',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ };
+ return {
+ operation => '*',
+ operand1 => $dv,
+ operand2 =>
+ {
+ operation => '*',
+ operand1 => $lnk,
+ operand2 =>
+ {
+ operation => 'exp',
+ operand1 =>
+ {
+ operation => '*',
+ operand1 => $lnk,
+ operand2 => $tree->{'operand2'}
+ },
+ operand2 => undef
+ }
+ }
+ };
+
+
+ # If it's a function of the variable raised to another function of the variable...
+ } else {
+ # d[u^v] = exp(ln(u) * v) * ((vdu)/u + ln(u)dv)
+ my $lnu = {
+ operation => 'ln',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ };
+ my $dv = $self->differentiateTree($variable, $tree->{'operand2'});
+ my $vdu = {
+ operation => '*',
+ operand1 => $tree->{'operand2'},
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ return {
+ operation => '*',
+ operand1 =>
+ {
+ operation => 'exp',
+ operand1 =>
+ {
+ operation => '*',
+ operand1 => $lnu,
+ operand2 => $tree->{'operand2'}
+ },
+ operand2 => undef
+ },
+ operand2 =>
+ {
+ operation => '+',
+ operand1 =>
+ {
+ operation => '/',
+ operand1 => $vdu,
+ operand2 => $tree->{'operand1'}
+ },
+ operand2 =>
+ {
+ operation => '*',
+ operand1 => $lnu,
+ operand2 => $dv
+ }
+ }
+ };
+ }
+
+ # Natural logarithm
+ } elsif ($tree->{'operation'} =~ /^(\-?)ln$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[ln(u)] = du/u
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => '/',
+ operand1 => $du,
+ operand2 => $tree->{'operand1'}
+ }
+ };
+
+ # Exponential (e)
+ } elsif ($tree->{'operation'} =~ /^(\-?)exp$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[exp(u)] = exp(u)du
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => $du,
+ operand2 => $tree
+ };
+
+ # sin
+ } elsif ($tree->{'operation'} =~ /^(\-?)sin$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[sin(u)] = cos(u)du
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => "${neg}cos",
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ };
+
+ # cos
+ } elsif ($tree->{'operation'} =~ /^(\-?)cos$/) {
+ # Stash negativity.
+ my $neg = $1 eq '-' ? '' : '-';
+
+ # d[cos(u)] = -sin(u)du
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => "${neg}sin",
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ };
+
+ # tan
+ } elsif ($tree->{'operation'} =~ /^(\-?)tan$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[tan(u)] = (sec(u))^2 * du
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => '*',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 =>
+ {
+ operation => "sec",
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ },
+ operand2 => 2
+ }
+ }
+ };
+
+ # sec
+ } elsif ($tree->{'operation'} =~ /^(\-?)sec$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # Convert to 1/cos and differentiate.
+ return $self->differentiateTree($variable, {
+ operation => '/',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => 'cos',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ });
+
+ # cosec
+ } elsif ($tree->{'operation'} =~ /^(\-?)cosec$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # Convert to 1/sin and differentiate.
+ return $self->differentiateTree($variable, {
+ operation => '/',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => 'sin',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ });
+
+ # cot
+ } elsif ($tree->{'operation'} =~ /^(\-?)cot$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # Convert to 1/tan and differentiate.
+ return $self->differentiateTree($variable, {
+ operation => '/',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => 'tan',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ });
+
+ # sinh
+ } elsif ($tree->{'operation'} =~ /^(\-?)sinh$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[sinh(u)] = cosh(u)du
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => "${neg}cosh",
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ };
+
+ # cosh
+ } elsif ($tree->{'operation'} =~ /^(\-?)cosh$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[cosh(u)] = sinh(u)du
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => "${neg}sinh",
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ };
+
+ # tanh
+ } elsif ($tree->{'operation'} =~ /^(\-?)tanh$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[tanh(u)] = (sech(u))^2 * du
+ my $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ return {
+ operation => '*',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => '*',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 =>
+ {
+ operation => "sech",
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ },
+ operand2 => 2
+ }
+ }
+ };
+
+ # sech
+ } elsif ($tree->{'operation'} =~ /^(\-?)sech$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # Convert to 1/cosh and differentiate.
+ return $self->differentiateTree($variable, {
+ operation => '/',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => 'cosh',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ });
+
+ # cosech
+ } elsif ($tree->{'operation'} =~ /^(\-?)cosech$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # Convert to 1/sinh and differentiate.
+ return $self->differentiateTree($variable, {
+ operation => '/',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => 'sinh',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ });
+
+ # coth
+ } elsif ($tree->{'operation'} =~ /^(\-?)coth$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # Convert to 1/tanh and differentiate.
+ return $self->differentiateTree($variable, {
+ operation => '/',
+ operand1 => "${neg}1",
+ operand2 =>
+ {
+ operation => 'tanh',
+ operand1 => $tree->{'operand1'},
+ operand2 => undef
+ }
+ });
+
+ # asin
+ } elsif ($tree->{'operation'} =~ /^(\-?)asin$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[asin(u)] = du / (1 - u^2)^0.5
+ my $du;
+ if ($neg) {
+ $du = {
+ operation => '-',
+ operand1 => '0',
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ } else {
+ $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ }
+ return {
+ operation => '/',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 =>
+ {
+ operation => '-',
+ operand1 => 1,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand1'},
+ operand2 => 2
+ }
+ },
+ operand2 => 0.5
+ }
+ };
+
+ # acos
+ } elsif ($tree->{'operation'} =~ /^(\-?)acos$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[acos(u)] = -du / (1 - u^2)^0.5
+ my $du;
+ if ($neg) {
+ $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ } else {
+ $du = {
+ operation => '-',
+ operand1 => '0',
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ }
+ return {
+ operation => '/',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 =>
+ {
+ operation => '-',
+ operand1 => 1,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand1'},
+ operand2 => 2
+ }
+ },
+ operand2 => 0.5
+ }
+ };
+
+ # atan
+ } elsif ($tree->{'operation'} =~ /^(\-?)atan$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[atan(u)] = du / (1 + u^2)
+ my $du;
+ if ($neg) {
+ $du = {
+ operation => '-',
+ operand1 => '0',
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ } else {
+ $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ }
+ return {
+ operation => '/',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '+',
+ operand1 => 1,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand1'},
+ operand2 => 2
+ }
+ }
+ };
+
+ # asinh
+ } elsif ($tree->{'operation'} =~ /^(\-?)asinh$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[asinh(u)] = du / (1 + u^2)^0.5
+ my $du;
+ if ($neg) {
+ $du = {
+ operation => '-',
+ operand1 => '0',
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ } else {
+ $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ }
+ return {
+ operation => '/',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 =>
+ {
+ operation => '+',
+ operand1 => 1,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand1'},
+ operand2 => 2
+ }
+ },
+ operand2 => 0.5
+ }
+ };
+
+ # acosh
+ } elsif ($tree->{'operation'} =~ /^(\-?)acosh$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[acosh(u)] = du / (u^2 - 1)^0.5
+ my $du;
+ if ($neg) {
+ $du = {
+ operation => '-',
+ operand1 => '0',
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ } else {
+ $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ }
+ return {
+ operation => '/',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 =>
+ {
+ operation => '-',
+ operand1 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand1'},
+ operand2 => 2
+ },
+ operand2 => 1
+ },
+ operand2 => 0.5
+ }
+ };
+
+ # atanh
+ } elsif ($tree->{'operation'} =~ /^(\-?)atanh$/) {
+ # Stash negativity.
+ my $neg = $1;
+
+ # d[atanh(u)] = du / (1 - u^2)
+ my $du;
+ if ($neg) {
+ $du = {
+ operation => '-',
+ operand1 => '0',
+ operand2 => $self->differentiateTree($variable, $tree->{'operand1'})
+ };
+ } else {
+ $du = $self->differentiateTree($variable, $tree->{'operand1'});
+ }
+ return {
+ operation => '/',
+ operand1 => $du,
+ operand2 =>
+ {
+ operation => '-',
+ operand1 => 1,
+ operand2 =>
+ {
+ operation => '^',
+ operand1 => $tree->{'operand1'},
+ operand2 => 2
+ }
+ }
+ };
+
+ # Otherwise, we don't know what it is.
+ } else {
+ $self->{'error'} = "Could not differentiate " . $self->prettyPrint($tree);
+ die;
+ }
+ }
+}
+
+1;
+
+
+
Added: branches/upstream/libmath-calculus-differentiate-perl/current/MANIFEST
URL: http://svn.debian.org/wsvn/branches/upstream/libmath-calculus-differentiate-perl/current/MANIFEST?rev=20086&op=file
==============================================================================
--- branches/upstream/libmath-calculus-differentiate-perl/current/MANIFEST (added)
+++ branches/upstream/libmath-calculus-differentiate-perl/current/MANIFEST Sun May 18 14:56:16 2008
@@ -1,0 +1,7 @@
+Changes
+Differentiate.pm
+Makefile.PL
+MANIFEST
+README
+test.pl
+META.yml Module meta-data (added by MakeMaker)
Added: branches/upstream/libmath-calculus-differentiate-perl/current/META.yml
URL: http://svn.debian.org/wsvn/branches/upstream/libmath-calculus-differentiate-perl/current/META.yml?rev=20086&op=file
==============================================================================
--- branches/upstream/libmath-calculus-differentiate-perl/current/META.yml (added)
+++ branches/upstream/libmath-calculus-differentiate-perl/current/META.yml Sun May 18 14:56:16 2008
@@ -1,0 +1,11 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: Math-Calculus-Differentiate
+version: 0.3
+version_from: Differentiate.pm
+installdirs: site
+requires:
+ Math::Calculus::Expression: 0.1
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.17
Added: branches/upstream/libmath-calculus-differentiate-perl/current/Makefile.PL
URL: http://svn.debian.org/wsvn/branches/upstream/libmath-calculus-differentiate-perl/current/Makefile.PL?rev=20086&op=file
==============================================================================
--- branches/upstream/libmath-calculus-differentiate-perl/current/Makefile.PL (added)
+++ branches/upstream/libmath-calculus-differentiate-perl/current/Makefile.PL Sun May 18 14:56:16 2008
@@ -1,0 +1,11 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'Math::Calculus::Differentiate',
+ 'VERSION_FROM' => 'Differentiate.pm', # finds $VERSION
+ 'PREREQ_PM' => {Math::Calculus::Expression => 0.1},
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'Differentiate.pm', # retrieve abstract from module
+ AUTHOR => 'J. Worthington <jonathan at jwcs.net>') : ()),
+);
Added: branches/upstream/libmath-calculus-differentiate-perl/current/README
URL: http://svn.debian.org/wsvn/branches/upstream/libmath-calculus-differentiate-perl/current/README?rev=20086&op=file
==============================================================================
--- branches/upstream/libmath-calculus-differentiate-perl/current/README (added)
+++ branches/upstream/libmath-calculus-differentiate-perl/current/README Sun May 18 14:56:16 2008
@@ -1,0 +1,34 @@
+Math::Calculus::Differentiate version 0.3.0
+===========================================
+
+Math::Calculus::Differentiate takes an algebraic expression (e.g. in
+the form x^2 + 5*x + sin(x)), differentiates it and returns the
+derivative in the same format (e.g. 2*x + 5 + cos(x)). In understands
+the operators +, -, *, / and ^ (raising to a power) as well as the
+functions sin, cos, tan, sec, cosec, cot, sinh, cosh, tanh, sech,
+cosech, coth, asin, acos, atan, asinh, acosh, atanh, ln and exp.
+Functions are valid either side of all operators - that is, you can
+differentiate a function raised to the power of another function.
+Partial differentiation is supported to the extent that you can
+differentiate with respect to a single variable.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+This module requires Perl 5.6.0 or greater and the module
+Math::Calculus::Expression.
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2004 Jonathan Worthington
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
Added: branches/upstream/libmath-calculus-differentiate-perl/current/test.pl
URL: http://svn.debian.org/wsvn/branches/upstream/libmath-calculus-differentiate-perl/current/test.pl?rev=20086&op=file
==============================================================================
--- branches/upstream/libmath-calculus-differentiate-perl/current/test.pl (added)
+++ branches/upstream/libmath-calculus-differentiate-perl/current/test.pl Sun May 18 14:56:16 2008
@@ -1,0 +1,89 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+#########################
+
+use Test;
+BEGIN { plan tests => 12 }
+my $res;
+
+## BASIC MODULE TESTS
+
+# Check include of module works.
+use Math::Calculus::Differentiate;
+ok(1);
+
+# Create object.
+my $exp = Math::Calculus::Differentiate->new;
+ok($exp);
+
+# Add a variable.
+$res = $exp->addVariable('x');
+ok($res);
+
+
+## REGRESSION TESTS
+
+# d[x] = 1
+$exp->setExpression('x');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '1');
+
+# d[-x] = -1
+$exp->setExpression('-x');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '-1');
+
+# d[x^2 + 4*x + 5] = 2*x + 4
+$exp->setExpression('x^2 + 4*x + 5');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '2*x + 4');
+
+# d[sin(-2 * x)] = -2*cos(-2*x)
+$exp->setExpression('sin(-2 * x)');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '-2*cos(-2*x)');
+
+# d[asin(x)] = 1/(1 - x^2)^0.5
+$exp->setExpression('asin(x)');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '1/(1 - x^2)^0.5');
+
+# d[ln(x^2)] = (2*x)/x^2
+$exp->setExpression('ln(x^2)');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '(2*x)/x^2');
+
+# d[x^x] = exp(ln(x)*x)*(1 + ln(x))
+$exp->setExpression('x^x');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq 'exp(ln(x)*x)*(1 + ln(x))');
+
+# d[x/x] = 0
+$exp->setExpression('x/x');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '0');
+
+# d[x - x] = 0
+$exp->setExpression('x - x');
+$exp->differentiate('x');
+$exp->simplify;
+$res = $exp->getExpression;
+ok($res eq '0');
+
More information about the Pkg-perl-cvs-commits
mailing list