## Mat4.pm -- read and write version 4 MAT-file format files. # Copyright (C) 2002 Ralph Schleicher # Author: Ralph Schleicher # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, # or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. ## Commentary: # See "MAT-File Format, Version 5" from The MathWorks, for detailed # information about the MAT-file format. This document is installed # with Matlab as `$MATLAB/help/pdf_doc/matlab/matfile_format.pdf', # or visit and follow the links # "Documentation" -> "Matlab" -> "Printable Documentation". ## Code: package Mat4; require 5.000; require Exporter; @ISA = qw (Exporter); @EXPORT = qw (mat4_write mat4_read mat4_ctor mat4_rtoc mat4_main); use Config; # The matrix type we can read or write. We support numeric # matrices in IEEE double precision floating-point format. my $mat4_type = ($Config{byteorder} =~ /^1/) ? 0 : 1000; ## Write matrix to file. sub mat4_write { # Variable name. my $name = shift; # Number of rows. my $m = shift; # Number of columns. my $n = shift; # Matrix elements in column major layout, this is the native # Matlab storage layout for matrices. my @a = splice (@_, 0, $m * $n); # File handle. my $h = shift; # Type flag. my $type = $mat4_type; # No imaginary part. my $imag = 0; # Length of variable name including terminating null character. my $len = length ($name) + 1; # Encode and print matrix. print ($h pack ('l5Z*d*', $type, $m, $n, $imag, $len, $name, @a)); } ## Read matrix from file. sub mat4_read { # File handle. my $h = shift; # Input buffer. my $buf; # Read and decode matrix header. return undef if read ($h, $buf, 20) != 20; my ($type, $m, $n, $imag, $len) = unpack ('l5', $buf); return undef if $type != $mat4_type || $imag != 0; # Read and decode variable name. return undef if read ($h, $buf, $len) != $len; my $name = unpack ('Z*', $buf); # Read and decode matrix elements. $len = $m * $n * 8; return undef if read ($h, $buf, $len) != $len; my @a = unpack ('d*', $buf); # Return values. ($name, $m, $n, @a); } ## Convert column major layout to row major layout. sub mat4_ctor { # Number of rows. my $m = shift; # Number of columns. my $n = shift; # Array elements. my @a = splice (@_, 0, $m * $n); # Row major layout. my @b = (); for (my $j = 0; $j < $n; ++$j) { for (my $i = 0; $i < $m; ++$i) { push (@b, $a[$i * $n + $j]); } } @b; } ## Convert row major layout to column major layout. sub mat4_rtoc { # Number of rows. my $m = shift; # Number of columns. my $n = shift; # Array elements. my @a = splice (@_, 0, $m * $n); # Column major layout. my @b = (); for (my $i = 0; $i < $m; ++$i) { for (my $j = 0; $j < $n; ++$j) { push (@b, $a[$j * $m + $i]); } } @b; } ## Test program. # $ perl -e 'use Mat4; mat4_main ()' # foo[3][2] = {0, 1, 2, 3, 4, 5} # bar[1][4] = {6, 7, 8, 9} # baz[0][0] = {} # # >> load mat4 # >> whos # Name Size Bytes Class # # bar 1x4 32 double array # baz 0x0 0 double array # foo 3x2 48 double array # # Grand total is 10 elements using 80 bytes # # >> foo # foo = # 0 3 # 1 4 # 2 5 # >> bar # bar = # 6 7 8 9 # >> baz # baz = # [] # >> sub mat4_main { open (MAT, '> mat4.mat') || die ("mat4.mat: $!\n"); mat4_write ('foo', 3, 2, (0, 1, 2, 3, 4, 5), *MAT); mat4_write ('bar', 1, 4, (6, 7, 8, 9), *MAT); mat4_write ('baz', 0, 0, (), *MAT); open (MAT, '< mat4.mat') || die ("mat4.mat: $!\n"); while ((($name, $m, $n, @a) = mat4_read (*MAT)) >= 3) { printf ("%s[%d][%d] = {%s}\n", $name, $m, $n, join (', ', @a)); } } 1; ## Mat4.pm ends here