# ITIID : $ITI$ $Header $__Header$
# Author : Ulrich Pfeifer
# Created On : Tue Oct 24 18:34:08 1995
# Last Modified By: Ulrich Pfeifer
# Last Modified On: Fri Sep 14 21:57:54 2001
# Status : Unknown, Use with caution!
# Copyright (C) 2001, Brian J. Watson <bjbrew@power.net>, all rights reserved.
# Copyright (C) 2001, Ulrich Pfeifer <pfeifer@wait.de>, all rights reserved.
# Copyright (C) 1995, Universität Dortmund, all rights reserved.
# Copyright (C) 2001, Matthew Brett <matthew.brett@mrc-cbu.cam.ac.uk>
# Permission to use this software is granted under the same
# restrictions as for Perl itself.
# Revision 0.3 2001/04/17 11:10:15
# Extensions from Brian Watson
# Revision 0.2 1996/07/10 17:48:14 pfeifer
# Fixes from Mike Beachy <beachy@chem.columbia.edu>
# Revision 0.1 1995/10/25 09:48:39 pfeifer
Math::Matrix - Multiply and invert Matrices
The following methods are available:
Constructor arguments are a list of references to arrays of the same
length. The arrays are copied. The method returns B<undef> in case of
$a = new Math::Matrix ([rand,rand,rand],
If you call C<new> as method, a zero filled matrix with identical deminsions is returned.
You can clone a matrix by calling:
You can determine the dimensions of a matrix by calling:
Concatenates two matrices of same row count. The result is a new
matrix or B<undef> in case of error.
$b = new Math::Matrix ([rand],[rand],[rand]);
Returns the transposed matrix. This is the matrix where colums and
rows of the argument matrix are swaped.
Multiplies two matrices where the length of the rows in the first
matrix is the same as the length of the columns in the second
matrix. Returns the product or B<undef> in case of error.
Solves a equation system given by the matrix. The number of colums
must be greater than the number of rows. If variables are dependent
from each other, the second and all further of the dependent
coefficients are 0. This means the method can handle such systems. The
method returns a matrix containing the solutions in its columns or
B<undef> in case of error.
Multiplies a matrix and a scalar resulting in a matrix of the same
dimensions with each element scaled with the scalar.
$a->multiply_scalar(2); scale matrix by factor 2
Add two matrices of the same dimensions.
Shorthand for C<add($other-E<gt>negative)>
Decide if two matrices are equal. Beware of rounding errors!
Compute the determinant of a matrix.
Compute the dot product of two vectors.
Compute the absolute value of a vector.
Compute the cross-product of vectors.
Prints the matrix on STDOUT. If the method has additional parameters,
these are printed before the matrix is printed.
$a = new Math::Matrix ([rand,rand,rand],
$x = new Math::Matrix ([rand,rand,rand]);
$E = $a->concat($x->transpose);
$E->print("Equation system\n");
$s->print("Solutions s\n");
$a->multiply($s)->print("A*s\n");
Ulrich Pfeifer E<lt>F<pfeifer@ls6.informatik.uni-dortmund.de>E<gt>
Brian J. Watson E<lt>F<bjbrew@power.net>E<gt>
Matthew Brett E<lt>matthew.brett@mrc-cbu.cam.ac.ukE<gt>
use vars
qw($VERSION $eps);
return "Math::Matrix $VERSION";
# Implement - array copy, inheritance
# class call - new matrix as input
# object call - creates matrix with same dimensions matrix
my $class = ref($that) || $that;
if (ref($that) && (@_ == 0)) { # object call no args -> copy matrix
push(@{$self}, [map {0} @{$_}]);
} else { # class call / object call -> matrix as input
my $len = scalar(@{$_[0]});
return undef if scalar(@{$_}) != $len;
bless $self, ref($that)||$that;
my $result = $self->clone();
return undef if scalar(@{$self}) != scalar(@{$other});
for my $i (0 .. $#{$self}) {
push @{$result->[$i]}, @{$other->[$i]};
for my $col (@{$self->[0]}) {
push(@{$result[$m++]}, $col);
for my $i (0 .. $#{$a}) {
$result += $a->[$i] * $b->[$i];
my $other = shift->transpose;
return undef if $#{$self->[0]} != $#{$other->[0]};
for my $col (@{$other}) {
push(@{$rescol}, vekpro($row,$col));
return undef if $mc <= $mr;
ROW: for(my $i = 0; $i <= $mr; $i++) {
# make diagonal element nonzero if possible
while (abs($m->[$i]->[$i]) < $eps) {
last ROW if $try++ > $mr;
my $row = splice(@{$m},$i,1);
for(my $k = 0; $k <= $mc; $k++) {
# subtract multiple of designated row from other rows
for(my $j = 0; $j <= $mr; $j++) {
for(my $k = 0; $k <= $mc; $k++) {
$m->[$j]->[$k] -= $m->[$i]->[$k] * $f;
# Answer is in augmented column
transpose $class->new(@{$m->transpose}[$mr+1 .. $mc]);
$out = $out . sprintf "%10.5f ", $col;
$out = $out . sprintf "\n";
my $class = ref($type) || $type;
push @$row, $i==$j ? 1 : 0;
my $result = $self->new();
my $last = $#{$self->[0]};
for my $i (0 .. $#{$self}) {
$result->[$i][$j] = $factor * $self->[$i][$j];
shift->multiply_scalar(-1);
$self->add($other->negative);
for my $i (0 .. $#{$A}) {
$A->[$i][$j] == $B->[$i][$j] or $ok=0;
my $result = $self->new();
if $#{$self} != $#{$other};
my $last= $#{$self->[0]};
if $last != $#{$other->[0]};
for my $i (0 .. $#{$self}) {
$result->[$i][$j] = $self->[$i][$j] + $other->[$i][$j];
my $result = $class->new([]);
for my $i (0..$#{$self}) {
push @{$result->[$i]}, $self->[$i][$j];
my $last= $#{$self->[0]};
unless $last == $#{$self};
foreach my $col (0..$last) {
my $matrix = $self->slice(0..$col-1,$col+1..$last);
$matrix = $class->new(@$matrix[1..$last]);
my $term += $matrix->determinant();
$term *= $self->[0][$col];
$term *= $col % 2 ? -1 : 1;
$vector1 = $vector1->transpose()
$vector2 = $vector2->transpose()
unless @{$vector2->[0]} == 1;
unless @{$vector2->[0]} == 1;
return $vector1->multiply($vector2)->[0][0];
sqrt $vector->dot_product($vector);
my $length = $vector->absolute();
$vector->multiply_scalar(1 / $length);
my $class = ref($vectors);
my $dimensions = @{$vectors->[0]};
unless $dimensions == @$vectors + 1;
foreach my $column (0..$dimensions-1) {
my $tmp = $vectors->slice(0..$column-1,
$column+1..$dimensions-1);
my $scalar = $tmp->determinant;
$scalar *= ($column % 2) ? -1 : 1;
my $axis = $class->new(\@axis);
$axis = $axis->multiply_scalar(($dimensions % 2) ? 1 : -1);