NAME

Math::Algebra::Symbols - Symbolic Manipulation in Perl

SYNOPSIS

use Math::Algebra::Symbols;

$x = symbols(qw(x));

$y = ($x**8 - 1) / ($x-1);

print "y=$y\n";

# y=1+$x+$x**2+$x**3+$x**4+$x**5+$x**6+$x**7

DESCRIPTION

This package supplies a set of functions and operators to manipulate operator expressions algebraically. These expressions are constructed from "Symbols" and "Operators" using the familiar Perl syntax.

Symbols

Symbols are created with the exported symbols() constructor routine:

use Math::Algebra::Symbols;

my ($x, $y, $i, $o) = symbols(qw(x y i 1));

print "$x $y $i $o\n";

# $x $y $i 1

The symbols() routine constructs references to symbolic variables and symbolic constants from a list of names and integer constants.

The special symbol i is recognized as the square root of -1.

In the example above, two symbolic variables: $x, $y are created and two symbolic constants: $i with value square root of -1 and $o with value 1.

If you wish to use a different name for the constructor routine, say S:

use Math::Algebra::Symbols symbols=>'S';

my ($x, $y, $i, $o) = S(qw(x y i 1));

print "$x $y $i $o\n";

# $x $y $i 1

If you wish to use big integers from Math::BigInt:

use Math::Algebra::Symbols BigInt=>1;

my $z = symbols('1234567890987654321/1234567890987654321');

print "$z\n";

# 1

Operators

"Symbols" can be combined with "Operators" to create symbolic expressions:

Arithmetic operators

Arithmetic Operators: + - * / **
use Math::Algebra::Symbols;

($x, $y) = symbols(qw(x y));

$z = ($x**2-$y**2)/($x-$y);

print "$z\n";

# $x+$y

The power operator ** expects an integer constant on its right hand side.

The auto assign versions of these operators: += -= *= /= all work courtesy of Perl Auto-Magical Operator Generation.

Square root Operator: sqrt
use Math::Algebra::Symbols;

$x = symbols(qw(x));

$z = sqrt(-$x**2);

print "$z\n";

# $i*$x

Relational operators

Relational operator: ==
use Math::Algebra::Symbols;

($x, $y) = symbols(qw(x y));

$z = ($x**2-$y**2)/($x+$y) == $x - $y;

print "$z\n";

# 1

The relational equality operator == compares two symbolic expressions and returns TRUE(1) or FALSE(0) accordingly.

Relational operator: eq
use Math::Algebra::Symbols;

($x, $v, $t) = symbols(qw(x v t));

$z = ($x / $t eq $v)->solve(qw(x in terms of v t));

print "x=$z\n";

# x=$v*$t

The relational operator eq is in fact a synonym for the minus - operator, with the expectation that later on the solve() function will be used to simplify and rearrange the equation.

Complex operators

Complex operators: the dot operator: ^
use Math::Algebra::Symbols;

($a, $b, $i) = symbols(qw(a b i));

$z = ($a+$i*$b)^($a-$i*$b);

print "$z\n";

# $a**2-$b**2

Note the use of brackets. The ^ operator has low priority.

The ^ operator treats its left hand and right hand arguments as complex numbers, which in turn are regarded as two dimensional vectors to which the vector dot product is applied.

Complex operators: the cross operator: x
use Math::Algebra::Symbols;

($x, $i) = symbols(qw(x i));

$z = $i*$x x $x;

print "$z\n";

# $x**2

The x operator treats its left hand and right hand arguments as complex numbers, which in turn are regarded as two dimensional vectors defining the sides of a parallelogram. The x operator returns the area of this parallelogram.

Note the space before the x, otherwise Perl is unable to disambiguate the expression correctly.

Complex operators: the conjugate operator: ~
use Math::Algebra::Symbols;

($x, $y, $i) = symbols(qw(x y i));

$z = $x+$i*$y;

print ~$z, "\n";

# $x-$i*$y

The ~ operator returns the complex conjugate of its right hand side.

Complex operators: the modulus operator: abs
use Math::Algebra::Symbols;

($x, $i) = symbols(qw(x i));

$z = abs($x+$i*$x);

print "$z\n";

# sqrt(2)*$x

The abs operator returns the modulus (length) of its right hand side.

Complex operators: the unit operator: !
use Math::Algebra::Symbols;

$i = symbols(qw(i));

print !$i, "\n";

# $i

The ! operator returns a complex number of unit length pointing in the same direction as its right hand side.

Functions

Complex functions

Complex functions: re and im
use Math::Algebra::Symbols;

($x, $i) = symbols(qw(x i));

$R = re $i*$x;
$I = im $i*$x;

print "$R $I\n";

# 0 $x

The re and im functions return an expression which represents the real and iumaginary parts of the expression, assuming that symbolic variables represent real numbers.

Functions for simplifying and solving equations

Simplifying equations: sub()
use Math::Algebra::Symbols;

($x, $y) = symbols(qw(x y));

$e = 1+$x+'1/2'*$x**2+'1/6'*$x**3+'1/24'*$x**4+'1/120'*$x**5; #1

$e2 = $e->sub(x=>$y**2, z=>2);   #2
$e3 = $e->sub(x=>1);             #3

print "$e2\n\n$e3\n\n";

# 1+$y**2+1/2*$y**4+1/6*$y**6+1/24*$y**8+1/120*$y**10

# 163/60

The quotes in line #1 are used to stop Perl evaluating the constant fractions as decimals, they are instead handed directly to the "Symbols" constructor for interpretation as symbolic fractions.

The sub() function example on line #2 demonstrates replacing variables with expressions. The replacement specified for z has no effect as z is not present in this equation.

Line #3 demonstrates the resulting rational fraction that arises when all the variables have been replaced by constants. This package does not convert fractions to decimal expressions in case there is a loss of acuracy, however:

$e3 =~ /^(\d+)\/(\d+)$/;
$result = $1/$2;

or similar will produce approximate results.

Solving equations: solve()
use Math::Algebra::Symbols;

($x, $v, $t) = symbols(qw(x v t));

$z = ($v eq $x / $t)->solve(qw(x in terms of v t)); #1

print "x=$z\n";

# x=$v*$t

solve() assumes that the equation on the left hand side is equal to zero, applies various simplifications, then attempts to rearrange the equation to obtain an equation for the first variable in the parameter list assuming that the other terms mentioned in the parameter list are known constants. There may of course be other unknown free variables in the equation to be solved: the proposed solution is automatically tested against the original equation to check that the proposed solution removes these variables, an error is reported if it does not.

Example Expressions:

use Math::Algebra::Symbols;

($a, $b, $x, $y, $i) = symbols(qw(a b x y i));

  print $i x 1, "\n";              # Cross product
# 1

  print $i^1,   "\n";              # Dot product - different vectors
# 0

  print $i^$i,  "\n";              # Dot product - same vector
# 1

  print abs $i, "\n";              # Length of unit vector
# 1

  print ~($a+$b) == ~$a+~$b, "\n"; # Conjugation is distributive
# 1                                  over addition

  print ~($a*$b) == ~$a*~$b, "\n"; # Conjugation is distributive
# 1                                  over multiplication

  print ~($a**2) == (~$a)**2,"\n"; # Conjugation is distributive
# 1                                  over power

  print  abs(!($x+$y*$i))==1,"\n"; # Length of unit vector
# 1

  print                            # Length of product = product of lengths
        abs($a+$i*$b)*abs($x+$i*$y) ==
       abs(($a+$i*$b)*   ($x+$i*$y)), "\n";
# 1  

Example of Equation Solving: the focii of a hyperbola:

use Math::Algebra::Symbols;
($a, $b, $x, $y, $i, $o) = symbols(qw(a b x y i 1));

print
"Hyperbola: Constant difference between distances from focii to locus of y=1/x",
"\n  Assume by symmetry the focii are on ",
"\n    the line y=x:                     ",  $f1 = $x + $i * $x,
"\n  and equidistant from the origin:    ",  $f2 = -$f1,
"\n  Choose a convenient point on y=1/x: ",  $a = $o+$i,
"\n        and a general point on y=1/x: ",  $b = $y+$i/$y,
"\n  Difference in distances from focii",
"\n    From convenient point:            ",  $A = abs($a - $f2) - abs($a - $f1),  
"\n    From general point:               ",  $B = abs($b - $f2) + abs($b - $f1),
"\n\n  Solving for x we get:            x=", ($A eq $B)->solve(qw(x)),
"\n                         (should be: sqrt(2))",                        
"\n  Which is indeed constant, as was to be demonstrated\n";

This example demonstrates the power of symbolic processing by finding the focii of the curve y=1/x, and incidentally, demonstrating that this curve is a hyperbola.

EXPORT

The package exports the constructor, which by default is called

"Symbols"()

However, this can be overriden on the use statement:

use Math::Algebra::Symbols symbols=>S

which would instead request that the constructor routine should be called S() instead.

AUTHOR

Philip R Brenan at philiprbrenan@yahoo.com