Matrix2

2*2 matrix manipulation

PhilipRBrenan@yahoo.com, 2004, Perl License

Synopsis

Example t/matrix2.t

#_ Matrix _____________________________________________________________
# Test 2*2 matrices    
# philiprbrenan@yahoo.com, 2004, Perl License    
#______________________________________________________________________

use Math::Zap::Matrix2 identity=>i;
use Math::Zap::Vector2;
use Test::Simple tests=>8;

my ($a, $b, $c, $v);

$a = matrix2
 (8, 0,
  0, 8,
 );

$b = matrix2
 (4, 2,
  2, 4,
 );

$c = matrix2
 (2, 2,
  1, 2,
 );

$v = vector2(1,2);

ok($a/$a           == i());
ok($b/$b           == i());
ok($c/$c           == i());
ok(2/$a*$a/2       == i());
ok(($a+$b)/($a+$b) == i());
ok(($a-$c)/($a-$c) == i());
ok(-$a/-$a         == i());
ok(1/$a*($a*$v)    == $v);

Description

2*2 matrix manipulation

package Math::Zap::Matrix2;
$VERSION=1.07;
use Math::Zap::Vector2 check=>'vector2Check', is=>'vector2Is';
use Carp;
use constant debug => 0; # Debugging level

Constructors

new

Create a matrix

sub new($$$$)
 {my
  ($a11, $a12,
   $a21, $a22,
  ) = @_;

  my $m = round(bless(
   {11=>$a11, 12=>$a12,
    21=>$a21, 22=>$a22,
   }));
  singular($m, 1);
  $m;
 }

matrix2

Create a matrix. Synonym for "new".

sub matrix2($$$$)
 {new($_[0],$_[1],$_[2],$_[3]);
 }

identity

Identity matrix

sub identity()
 {bless
   {11=>1, 21=>0,                              
    12=>0, 22=>1,                              
   }; 
 }

new2v

Create a matrix from two vectors

sub new2v($$)
 {vector2Check(@_) if debug;
  my ($a, $b, $c) =  @_;
  my $m = round(bless(
   {11=>$a->{x}, 12=>$b->{x},
    21=>$a->{y}, 22=>$b->{y},
   }));
  singular($m, 1);
  $m;
 }

Methods

check

Check its a matrix

sub check(@)
 {if (debug)
   {for my $m(@_)
     {confess "$m is not a matrix2" unless ref($m) eq __PACKAGE__;
     } 
   }
  return (@_)
 }

is

Test its a matrix

sub is(@)
 {for my $m(@_)
   {return 0 unless ref($m) eq __PACKAGE__;
   }
  'matrix2';
 }

accuracy

Get/Set accuracy

my $accuracy = 1e-10;

sub accuracy
 {return $accuracy unless scalar(@_);
  $accuracy = shift();
 }

round

Round: round to nearest integer if within accuracy of that integer

sub round($)
 {unless (debug)
   {return $_[0];
   }
  else
   {my ($a) = @_;
    for my $k(keys(%$a))
     {my $n = $a->{$k};
      my $N = int($n);
      $a->{$k} = $N if abs($n-$N) < $accuracy;
     }
    return $a;
   }
 }

singular

Singular matrix?

sub singular($$)
 {my $m = shift;  # Matrix   
  my $a = 1e-2;   # Accuracy
  my $A = shift;  # Action 0: return indicator, 1: confess 
  my $n = abs
    ($m->{11} * $m->{22} -                                        
     $m->{12} * $m->{21})
    < $a;
  confess "Singular matrix2" if $n and $A;
  $n;      
 }

clone

Create a matrix from another matrix

sub clone($)
 {my ($m) = check(@_); # Matrix
  round bless
   {11=>$m->{11}, 12=>$m->{12},
    21=>$m->{21}, 22=>$m->{22},
   }; 
 }

print

Print matrix

sub print($)
 {my ($m) = check(@_); # Matrix 
  'matrix2('.$m->{11}.', '.$m->{12}. 
        ', '.$m->{21}.', '.$m->{22}.
  ')';
 } 

add

Add matrices

sub add($$)
 {my ($a, $b) = check(@_); # Matrices
  my $m = round bless
   {11=>$a->{11}+$b->{11}, 12=>$a->{12}+$b->{12}, 
    21=>$a->{21}+$b->{21}, 22=>$a->{22}+$b->{22}, 
   }; 
  singular($m, 1);
  $m;
 }

negate

Negate matrix

sub negate($)
 {my ($a) = check(@_); # Matrices
  my $m = round bless
   {11=>-$a->{11}, 12=>-$a->{12},
    21=>-$a->{21}, 22=>-$a->{22},
   }; 
  singular($m, 1);
  $m;
 }

subtract

Subtract matrices

sub subtract($$)
 {my ($a, $b) = check(@_); # Matrices
  my $m = round bless
   {11=>$a->{11}-$b->{11}, 12=>$a->{12}-$b->{12},
    21=>$a->{21}-$b->{21}, 22=>$a->{22}-$b->{22},
   }; 
  singular($m, 1);
  $m;
 }

matrixVectorMultiply

Vector = Matrix * Vector

sub matrixVectorMultiply($$)
 {       check(@_[0..0]) if debug; # Matrix
  vector2Check(@_[1..1]) if debug; # Vector 
  my ($a, $b) = @_;
  vector2
   ($a->{11}*$b->{x}+$a->{12}*$b->{y},
    $a->{21}*$b->{x}+$a->{22}*$b->{y},
   );
 }

matrixScalarMultiply

Matrix = Matrix * scalar

sub matrixScalarMultiply($$)
 {my ($a) = check(@_[0..0]); # Matrix
  my ($b) = @_[1..1];        # Scalar
  confess "$b is not a scalar" if ref($b);   
  round bless
   {11=>$a->{11}*$b, 12=>$a->{12}*$b,
    21=>$a->{21}*$b, 22=>$a->{22}*$b,
   }; 
 }

matrixMatrixMultiply

Matrix = Matrix * Matrix

sub matrixMatrixMultiply($$)
 {my ($a, $b) = check(@_); # Matrices
  round bless
   {11=>$a->{11}*$b->{11}+$a->{12}*$b->{21}, 12=>$a->{11}*$b->{12}+$a->{12}*$b->{22},
    21=>$a->{21}*$b->{11}+$a->{22}*$b->{21}, 22=>$a->{21}*$b->{12}+$a->{22}*$b->{22},
   }; 
 }

matrixScalarDivide

Matrix=Matrix / non zero scalar

sub matrixScalarDivide($$)
 {my ($a) = check(@_[0..0]); # Matrices
  my ($b) = @_[1..1];        # Scalar
  confess "$b is not a scalar" if ref($b);   
  confess "$b is zero"         if $b == 0;   
  round bless
   {11=>$a->{11}/$b, 12=>$a->{12}/$b,
    21=>$a->{21}/$b, 22=>$a->{22}/$b,
   }; 
 }

det

Determinant of matrix.

sub det($)
 {my ($a) = check(@_); # Matrices

+$a->{11}*$a->{22}
-$a->{12}*$a->{21}
 }

inverse

Inverse of matrix

sub inverse($)
 {my ($a) = check(@_); # Matrices

  my $d = det($a);
  return undef if $d == 0;

  round bless
   {11=> $a->{22}/$d, 21=>-$a->{21}/$d,
    12=>-$a->{12}/$d, 22=> $a->{11}/$d,
   }; 
 }

rotate

Rotation matrix: rotate anti-clockwise by t radians

sub rotate($)
 {my ($a) = @_;
   bless
   {11=>cos($t), 21=>-sin($t),                              
    12=>sin($t), 22=> cos($t),                              
   }; 
 }

equals

Equals to within accuracy

sub equals($$)
 {my ($a, $b) = check(@_); # Matrices
  abs($a->{11}-$b->{11}) < $accuracy and
  abs($a->{12}-$b->{12}) < $accuracy and

  abs($a->{21}-$b->{21}) < $accuracy and
  abs($a->{22}-$b->{22}) < $accuracy;
 }

Operators

Operator overloads

use overload
 '+'        => \&add3,      # Add two vectors
 '-'        => \&subtract3, # Subtract one vector from another
 '*'        => \&multiply3, # Times by a scalar, or vector dot product 
 '/'        => \&divide3,   # Divide by a scalar
 '!'        => \&det3,      # Determinant                       
 '=='       => \&equals3,   # Equals (to accuracy)
 '""'       => \&print3,    # Print
 'fallback' => FALSE;

add operator

Add operator.

sub add3
 {my ($a, $b) = @_;
  $a->add($b);
 }

subtract operator

Subtract operator.

sub subtract3
 {my ($a, $b, $c) = @_;

  return $a->subtract($b) if $b;
  negate($a);
 }

multiply operator

Multiply operator.

sub multiply3
 {my ($a, $b) = @_;
  return $a->matrixScalarMultiply($b) unless ref($b);
  return $a->matrixVectorMultiply($b) if vector2Is($b);
  return $a->matrixMatrixMultiply($b) if is($b);
  confess "Cannot multiply $a by $b\n";
 }

divide operator

Divide operator.

sub divide3
 {my ($a, $b, $c) = @_;
  if (!ref($b))
   {return $a->matrixScalarDivide($b)            unless $c;
    return $a->inverse->matrixScalarMultiply($b) if     $c;
   }
  else 
   {return $a->inverse->matrixVectorMultiply($b) if vector2Is($b);
    return $a->matrixMatrixMultiply($b->inverse) if is($b);
    confess "Cannot multiply $a by $b\n";
   }
 }

equals operator

Equals operator.

sub equals3
 {my ($a, $b, $c) = @_;
  return $a->equals($b);
 }

determinant operator

Determinant of a matrix

sub det3
 {my ($a, $b, $c) = @_;
  $a->det;
 }

Print a vector.

sub print3
 {my ($a) = @_;
  return $a->print;
 }

Exports

Export "matrix2", "identity"

use Math::Zap::Exports qw(
  matrix2  ($$$$)
  new2v    ($$)
  identity ()
 );

#_ Matrix2 ____________________________________________________________
# Package loaded successfully
#______________________________________________________________________

1;

Credits

Author

philiprbrenan@yahoo.com

philiprbrenan@yahoo.com, 2004

License

Perl License.