|
|
Re: Write binary MAT files in PERL
Posted:
Mar 7, 2012 3:36 PM
|
|
"Abhi " <abhishek.xtreme@gmail.com> writes:
> I was wondering if it is possible to write binary .mat files within > Perl. Matlab documention shows how to do this in C/C++, but I couldn't > find using Perl.
Everything is possible! Here's a quick hack I wrote some years ago. See mat4_main below for an example.
## Mat4.pm -- read and write version 4 MAT-file format files.
# Copyright (C) 2002, 2004 Ralph Schleicher
# Version: $Id: Mat4.pm,v 1.3 2004/03/13 12:51:16 rs Exp $
# 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 <http://www.mathworks.com/support/> 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
|
|