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