[Scipy-svn] r3659 - in branches/io_new: . matlab tests
scipy-svn at scipy.org
scipy-svn at scipy.org
Fri Dec 14 18:33:56 EST 2007
Author: jarrod.millman
Date: 2007-12-14 17:33:47 -0600 (Fri, 14 Dec 2007)
New Revision: 3659
Added:
branches/io_new/matlab/
branches/io_new/matlab/mio.py
branches/io_new/matlab/mio4.py
branches/io_new/matlab/mio5.py
branches/io_new/matlab/miobase.py
Removed:
branches/io_new/mio.py
branches/io_new/mio4.py
branches/io_new/mio5.py
branches/io_new/miobase.py
Modified:
branches/io_new/__init__.py
branches/io_new/tests/test_mio.py
Log:
moved matlab code to new directory
Modified: branches/io_new/__init__.py
===================================================================
--- branches/io_new/__init__.py 2007-12-14 23:31:02 UTC (rev 3658)
+++ branches/io_new/__init__.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -8,7 +8,7 @@
from numpyio import packbits, unpackbits, bswap, fread, fwrite, \
convert_objectarray
# matfile read and write
-from mio import *
+from matlab.mio import loadmat, savemat
# netCDF file support
from netcdf import *
from npfile import npfile
Copied: branches/io_new/matlab/mio.py (from rev 3657, branches/io_new/mio.py)
===================================================================
--- branches/io_new/mio.py 2007-12-14 22:44:43 UTC (rev 3657)
+++ branches/io_new/matlab/mio.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -0,0 +1,133 @@
+# Authors: Travis Oliphant, Matthew Brett
+
+"""
+Module for reading and writing matlab (TM) .mat files
+"""
+
+import os
+import sys
+
+from scipy.io.matlab.mio4 import MatFile4Reader, MatFile4Writer
+from scipy.io.matlab.mio5 import MatFile5Reader, MatFile5Writer
+
+__all__ = ['find_mat_file', 'mat_reader_factory', 'loadmat', 'savemat']
+
+def find_mat_file(file_name, appendmat=True):
+ ''' Try to find .mat file on system path
+
+ file_name - file name string
+ append_mat - If True, and file_name does not end in '.mat', appends it
+ '''
+ if appendmat and file_name[-4:] == ".mat":
+ file_name = file_name[:-4]
+ if os.sep in file_name:
+ full_name = file_name
+ if appendmat:
+ full_name = file_name + ".mat"
+ else:
+ full_name = None
+ junk, file_name = os.path.split(file_name)
+ for path in [os.curdir] + list(sys.path):
+ test_name = os.path.join(path, file_name)
+ if appendmat:
+ test_name += ".mat"
+ try:
+ fid = open(test_name,'rb')
+ fid.close()
+ full_name = test_name
+ break
+ except IOError:
+ pass
+ return full_name
+
+def mat_reader_factory(file_name, appendmat=True, **kwargs):
+ """Create reader for matlab (TM) .mat format files
+
+ See docstring for loadmat for input options
+ """
+ if isinstance(file_name, basestring):
+ full_name = find_mat_file(file_name, appendmat)
+ if full_name is None:
+ raise IOError, "%s not found on the path." % file_name
+ byte_stream = open(full_name, 'rb')
+ else:
+ try:
+ file_name.read(0)
+ except AttributeError:
+ raise IOError, 'Reader needs file name or open file-like object'
+ byte_stream = file_name
+
+ MR = MatFile4Reader(byte_stream, **kwargs)
+ if MR.format_looks_right():
+ return MR
+ return MatFile5Reader(byte_stream, **kwargs)
+
+def loadmat(file_name, mdict=None, appendmat=True, basename='raw', **kwargs):
+ ''' Load Matlab(tm) file
+
+ file_name - Name of the mat file
+ (do not need .mat extension if appendmat==True)
+ If name not a full path name, search for the file on
+ the sys.path list and use the first one found (the
+ current directory is searched first).
+ Can also pass open file-like object
+ m_dict - optional dictionary in which to insert matfile variables
+ appendmat - True to append the .mat extension to the end of the
+ given filename, if not already present
+ base_name - base name for unnamed variables (unused in code)
+ byte_order - byte order ('native', 'little', 'BIG')
+ in ('native', '=')
+ or in ('little', '<')
+ or in ('BIG', '>')
+ mat_dtype - return arrays in same dtype as loaded into matlab
+ (instead of the dtype with which they are saved)
+ squeeze_me - whether to squeeze matrix dimensions or not
+ chars_as_strings - whether to convert char arrays to string arrays
+ mat_dtype - return matrices with datatype that matlab would load as
+ (rather than in the datatype matlab saves as)
+ matlab_compatible - returns matrices as would be loaded by matlab
+ (implies squeeze_me=False, chars_as_strings=False,
+ mat_dtype=True)
+
+ v4 (Level 1.0), v6 and v7.1 matfiles are supported.
+
+ '''
+ MR = mat_reader_factory(file_name, appendmat, **kwargs)
+ matfile_dict = MR.get_variables()
+ if mdict is not None:
+ mdict.update(matfile_dict)
+ else:
+ mdict = matfile_dict
+ return mdict
+
+def savemat(file_name, mdict, appendmat=True, format='4'):
+ """Save a dictionary of names and arrays into the MATLAB-style .mat file.
+
+ This saves the arrayobjects in the given dictionary to a matlab
+ style .mat file.
+
+ appendmat - if true, appends '.mat' extension to filename, if not present
+ format - '4' for matlab 4 mat files, '5' for matlab 5 onwards
+ """
+ file_is_string = isinstance(file_name, basestring)
+ if file_is_string:
+ if appendmat and file_name[-4:] != ".mat":
+ file_name = file_name + ".mat"
+ file_stream = open(file_name, 'wb')
+ else:
+ try:
+ file_name.write('')
+ except AttributeError:
+ raise IOError, 'Writer needs file name or writeable '\
+ 'file-like object'
+ file_stream = file_name
+
+ if format == '4':
+ MW = MatFile4Writer(file_stream)
+ elif format == '5':
+ MW = MatFile5Writer(file_stream)
+ else:
+ raise ValueError, 'Format should be 4 or 5'
+ MW.put_variables(mdict)
+ if file_is_string:
+ file_stream.close()
Copied: branches/io_new/matlab/mio4.py (from rev 3657, branches/io_new/mio4.py)
===================================================================
--- branches/io_new/mio4.py 2007-12-14 22:44:43 UTC (rev 3657)
+++ branches/io_new/matlab/mio4.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -0,0 +1,345 @@
+''' Classes for read / write of matlab (TM) 4 files
+'''
+
+import numpy as N
+
+from scipy.io.matlab.miobase import *
+
+miDOUBLE = 0
+miSINGLE = 1
+miINT32 = 2
+miINT16 = 3
+miUINT16 = 4
+miUINT8 = 5
+
+mdtypes_template = {
+ miDOUBLE: 'f8',
+ miSINGLE: 'f4',
+ miINT32: 'i4',
+ miINT16: 'i2',
+ miUINT16: 'u2',
+ miUINT8: 'u1',
+ 'header': [('mopt', 'i4'),
+ ('mrows', 'i4'),
+ ('ncols', 'i4'),
+ ('imagf', 'i4'),
+ ('namlen', 'i4')],
+ 'U1': 'U1',
+ }
+
+np_to_mtypes = {
+ 'f8': miDOUBLE,
+ 'c32': miDOUBLE,
+ 'c24': miDOUBLE,
+ 'c16': miDOUBLE,
+ 'f4': miSINGLE,
+ 'c8': miSINGLE,
+ 'i4': miINT32,
+ 'i2': miINT16,
+ 'u2': miUINT16,
+ 'u1': miUINT8,
+ 'S1': miUINT8,
+ }
+
+# matrix classes
+mxFULL_CLASS = 0
+mxCHAR_CLASS = 1
+mxSPARSE_CLASS = 2
+
+order_codes = {
+ 0: '<',
+ 1: '>',
+ 2: 'VAX D-float', #!
+ 3: 'VAX G-float',
+ 4: 'Cray', #!!
+ }
+
+
+class Mat4ArrayReader(MatArrayReader):
+ ''' Class for reading Mat4 arrays
+ '''
+
+ def matrix_getter_factory(self):
+ ''' Read header, return matrix getter '''
+ data = self.read_dtype(self.dtypes['header'])
+ header = {}
+ header['name'] = self.read_ztstring(data['namlen'])
+ if data['mopt'] < 0 or data['mopt'] > 5000:
+ ValueError, 'Mat 4 mopt wrong format, byteswapping problem?'
+ M,rest = divmod(data['mopt'], 1000)
+ O,rest = divmod(rest,100)
+ P,rest = divmod(rest,10)
+ T = rest
+ if O != 0:
+ raise ValueError, 'O in MOPT integer should be 0, wrong format?'
+ header['dtype'] = self.dtypes[P]
+ header['mclass'] = T
+ header['dims'] = (data['mrows'], data['ncols'])
+ header['is_complex'] = data['imagf'] == 1
+ remaining_bytes = header['dtype'].itemsize * N.product(header['dims'])
+ if header['is_complex'] and not header['mclass'] == mxSPARSE_CLASS:
+ remaining_bytes *= 2
+ next_pos = self.mat_stream.tell() + remaining_bytes
+ if T == mxFULL_CLASS:
+ getter = Mat4FullGetter(self, header)
+ elif T == mxCHAR_CLASS:
+ getter = Mat4CharGetter(self, header)
+ elif T == mxSPARSE_CLASS:
+ getter = Mat4SparseGetter(self, header)
+ else:
+ raise TypeError, 'No reader for class code %s' % T
+ getter.next_position = next_pos
+ return getter
+
+
+class Mat4MatrixGetter(MatMatrixGetter):
+
+ # Mat4 variables never global or logical
+ is_global = False
+ is_logical = False
+
+ def read_array(self, copy=True):
+ ''' Mat4 read array always uses header dtype and dims
+ copy - copies array if True
+ (buffer is usually read only)
+ a_dtype is assumed to be correct endianness
+ '''
+ dt = self.header['dtype']
+ dims = self.header['dims']
+ num_bytes = dt.itemsize
+ for d in dims:
+ num_bytes *= d
+ arr = N.ndarray(shape=dims,
+ dtype=dt,
+ buffer=self.mat_stream.read(num_bytes),
+ order='F')
+ if copy:
+ arr = arr.copy()
+ return arr
+
+
+class Mat4FullGetter(Mat4MatrixGetter):
+ def __init__(self, array_reader, header):
+ super(Mat4FullGetter, self).__init__(array_reader, header)
+ if header['is_complex']:
+ self.mat_dtype = N.dtype(N.complex128)
+ else:
+ self.mat_dtype = N.dtype(N.float64)
+
+ def get_raw_array(self):
+ if self.header['is_complex']:
+ # avoid array copy to save memory
+ res = self.read_array(copy=False)
+ res_j = self.read_array(copy=False)
+ return res + (res_j * 1j)
+ return self.read_array()
+
+
+class Mat4CharGetter(Mat4MatrixGetter):
+ def get_raw_array(self):
+ arr = self.read_array().astype(N.uint8)
+ # ascii to unicode
+ S = arr.tostring().decode('ascii')
+ return N.ndarray(shape=self.header['dims'],
+ dtype=N.dtype('U1'),
+ buffer = N.array(S)).copy()
+
+
+class Mat4SparseGetter(Mat4MatrixGetter):
+ ''' Read sparse matrix type
+
+ Matlab (TM) 4 real sparse arrays are saved in a N+1 by 3 array
+ format, where N is the number of non-zero values. Column 1 values
+ [0:N] are the (1-based) row indices of the each non-zero value,
+ column 2 [0:N] are the column indices, column 3 [0:N] are the
+ (real) values. The last values [-1,0:2] of the rows, column
+ indices are shape[0] and shape[1] respectively of the output
+ matrix. The last value for the values column is a padding 0. mrows
+ and ncols values from the header give the shape of the stored
+ matrix, here [N+1, 3]. Complex data is saved as a 4 column
+ matrix, where the fourth column contains the imaginary component;
+ the last value is again 0. Complex sparse data do _not_ have the
+ header imagf field set to True; the fact that the data are complex
+ is only detectable because there are 4 storage columns
+ '''
+ def get_raw_array(self):
+ res = self.read_array()
+ tmp = res[:-1,:]
+ dims = res[-1,0:2]
+ I = N.ascontiguousarray(tmp[:,0],dtype='intc') #fixes byte order also
+ J = N.ascontiguousarray(tmp[:,1],dtype='intc')
+ I -= 1 # for 1-based indexing
+ J -= 1
+ if res.shape[1] == 3:
+ V = N.ascontiguousarray(tmp[:,2],dtype='float')
+ else:
+ V = N.ascontiguousarray(tmp[:,2],dtype='complex')
+ V.imag = tmp[:,3]
+ if have_sparse:
+ return scipy.sparse.coo_matrix((V,(I,J)), dims)
+ return (dims, I, J, V)
+
+
+class MatFile4Reader(MatFileReader):
+ ''' Reader for Mat4 files '''
+ def __init__(self, mat_stream, *args, **kwargs):
+ self._array_reader = Mat4ArrayReader(
+ mat_stream,
+ None,
+ None,
+ )
+ super(MatFile4Reader, self).__init__(mat_stream, *args, **kwargs)
+ self._array_reader.processor_func = self.processor_func
+
+ def set_dtypes(self):
+ self.dtypes = self.convert_dtypes(mdtypes_template)
+ self._array_reader.dtypes = self.dtypes
+
+ def matrix_getter_factory(self):
+ return self._array_reader.matrix_getter_factory()
+
+ def format_looks_right(self):
+ # Mat4 files have a zero somewhere in first 4 bytes
+ self.mat_stream.seek(0)
+ mopt_bytes = N.ndarray(shape=(4,),
+ dtype=N.uint8,
+ buffer = self.mat_stream.read(4))
+ self.mat_stream.seek(0)
+ return 0 in mopt_bytes
+
+ def guess_byte_order(self):
+ self.mat_stream.seek(0)
+ mopt = self.read_dtype(N.dtype('i4'))
+ self.mat_stream.seek(0)
+ if mopt < 0 or mopt > 5000:
+ return ByteOrder.swapped_code
+ return ByteOrder.native_code
+
+
+class Mat4MatrixWriter(MatStreamWriter):
+
+ def write_header(self, P=0, T=0, imagf=0, dims=None):
+ ''' Write header for given data options
+ P - mat4 data type
+ T - mat4 matrix class
+ imagf - complex flag
+ dims - matrix dimensions
+ '''
+ if dims is None:
+ dims = self.arr.shape
+ header = N.empty((), mdtypes_template['header'])
+ M = not ByteOrder.little_endian
+ O = 0
+ header['mopt'] = (M * 1000 +
+ O * 100 +
+ P * 10 +
+ T)
+ header['mrows'] = dims[0]
+ header['ncols'] = dims[1]
+ header['imagf'] = imagf
+ header['namlen'] = len(self.name) + 1
+ self.write_bytes(header)
+ self.write_string(self.name + '\0')
+
+ def arr_to_2d(self):
+ self.arr = N.atleast_2d(self.arr)
+ dims = self.arr.shape
+ if len(dims) > 2:
+ self.arr = self.arr.reshape(-1,dims[-1])
+
+ def write(self):
+ assert False, 'Not implemented'
+
+
+class Mat4NumericWriter(Mat4MatrixWriter):
+
+ def write(self):
+ self.arr_to_2d()
+ imagf = self.arr.dtype.kind == 'c'
+ try:
+ P = np_to_mtypes[self.arr.dtype.str[1:]]
+ except KeyError:
+ if imagf:
+ self.arr = self.arr.astype('c128')
+ else:
+ self.arr = self.arr.astype('f8')
+ P = miDOUBLE
+ self.write_header(P=P,
+ T=mxFULL_CLASS,
+ imagf=imagf)
+ if imagf:
+ self.write_bytes(self.arr.real)
+ self.write_bytes(self.arr.imag)
+ else:
+ self.write_bytes(self.arr)
+
+
+class Mat4CharWriter(Mat4MatrixWriter):
+
+ def write(self):
+ self.arr_to_chars()
+ self.arr_to_2d()
+ dims = self.arr.shape
+ self.write_header(P=miUINT8,
+ T=mxCHAR_CLASS)
+ if self.arr.dtype.kind == 'U':
+ # Recode unicode to ascii
+ n_chars = N.product(dims)
+ st_arr = N.ndarray(shape=(),
+ dtype=self.arr_dtype_number(n_chars),
+ buffer=self.arr)
+ st = st_arr.item().encode('ascii')
+ self.arr = N.ndarray(shape=dims, dtype='S1', buffer=st)
+ self.write_bytes(self.arr)
+
+
+class Mat4SparseWriter(Mat4MatrixWriter):
+
+ def write(self):
+ ''' Sparse matrices are 2D
+ See docstring for Mat4SparseGetter
+ '''
+ imagf = self.arr.dtype.kind == 'c'
+ nnz = self.arr.nnz
+ ijd = N.zeros((nnz+1, 3+imagf), dtype='f8')
+ for i in range(nnz):
+ ijd[i,0], ijd[i,1] = self.arr.rowcol(i)
+ ijd[:-1,0:2] += 1 # 1 based indexing
+ if imagf:
+ ijd[:-1,2] = self.arr.data.real
+ ijd[:-1,3] = self.arr.data.imag
+ else:
+ ijd[:-1,2] = self.arr.data
+ ijd[-1,0:2] = self.arr.shape
+ self.write_header(P=miDOUBLE,
+ T=mxSPARSE_CLASS,
+ dims=ijd.shape)
+ self.write_bytes(ijd)
+
+
+def matrix_writer_factory(stream, arr, name):
+ ''' Factory function to return matrix writer given variable to write
+ stream - file or file-like stream to write to
+ arr - array to write
+ name - name in matlab (TM) workspace
+ '''
+ if have_sparse:
+ if scipy.sparse.issparse(arr):
+ return Mat4SparseWriter(stream, arr, name)
+ arr = N.array(arr)
+ dtt = arr.dtype.type
+ if dtt is N.object_:
+ raise TypeError, 'Cannot save object arrays in Mat4'
+ elif dtt is N.void:
+ raise TypeError, 'Cannot save void type arrays'
+ elif dtt in (N.unicode_, N.string_):
+ return Mat4CharWriter(stream, arr, name)
+ else:
+ return Mat4NumericWriter(stream, arr, name)
+
+
+class MatFile4Writer(MatFileWriter):
+
+ def put_variables(self, mdict):
+ for name, var in mdict.items():
+ matrix_writer_factory(self.file_stream, var, name).write()
Copied: branches/io_new/matlab/mio5.py (from rev 3657, branches/io_new/mio5.py)
===================================================================
--- branches/io_new/mio5.py 2007-12-14 22:44:43 UTC (rev 3657)
+++ branches/io_new/matlab/mio5.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -0,0 +1,807 @@
+''' Classes for read / write of matlab (TM) 5 files
+'''
+
+# Small fragments of current code adapted from matfile.py by Heiko
+# Henkelmann
+
+## Notice in matfile.py file
+
+# Copyright (c) 2003 Heiko Henkelmann
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+import zlib
+from copy import copy as pycopy
+from cStringIO import StringIO
+import numpy as N
+
+from scipy.io.matlab.miobase import *
+
+try: # Python 2.3 support
+ from sets import Set as set
+except:
+ pass
+
+miINT8 = 1
+miUINT8 = 2
+miINT16 = 3
+miUINT16 = 4
+miINT32 = 5
+miUINT32 = 6
+miSINGLE = 7
+miDOUBLE = 9
+miINT64 = 12
+miUINT64 = 13
+miMATRIX = 14
+miCOMPRESSED = 15
+miUTF8 = 16
+miUTF16 = 17
+miUTF32 = 18
+
+mxCELL_CLASS = 1
+mxSTRUCT_CLASS = 2
+mxOBJECT_CLASS = 3
+mxCHAR_CLASS = 4
+mxSPARSE_CLASS = 5
+mxDOUBLE_CLASS = 6
+mxSINGLE_CLASS = 7
+mxINT8_CLASS = 8
+mxUINT8_CLASS = 9
+mxINT16_CLASS = 10
+mxUINT16_CLASS = 11
+mxINT32_CLASS = 12
+mxUINT32_CLASS = 13
+
+mdtypes_template = {
+ miINT8: 'i1',
+ miUINT8: 'u1',
+ miINT16: 'i2',
+ miUINT16: 'u2',
+ miINT32: 'i4',
+ miUINT32: 'u4',
+ miSINGLE: 'f4',
+ miDOUBLE: 'f8',
+ miINT64: 'i8',
+ miUINT64: 'u8',
+ miUTF8: 'u1',
+ miUTF16: 'u2',
+ miUTF32: 'u4',
+ 'file_header': [('description', 'S116'),
+ ('subsystem_offset', 'i8'),
+ ('version', 'u2'),
+ ('endian_test', 'S2')],
+ 'tag_full': [('mdtype', 'u4'), ('byte_count', 'u4')],
+ 'array_flags': [('data_type', 'u4'),
+ ('byte_count', 'u4'),
+ ('flags_class','u4'),
+ ('nzmax', 'u4')],
+ 'U1': 'U1',
+ }
+
+mclass_dtypes_template = {
+ mxINT8_CLASS: 'i1',
+ mxUINT8_CLASS: 'u1',
+ mxINT16_CLASS: 'i2',
+ mxUINT16_CLASS: 'u2',
+ mxINT32_CLASS: 'i4',
+ mxUINT32_CLASS: 'u4',
+ mxSINGLE_CLASS: 'f4',
+ mxDOUBLE_CLASS: 'f8',
+ }
+
+
+np_to_mtypes = {
+ 'f8': miDOUBLE,
+ 'c32': miDOUBLE,
+ 'c24': miDOUBLE,
+ 'c16': miDOUBLE,
+ 'f4': miSINGLE,
+ 'c8': miSINGLE,
+ 'i1': miINT8,
+ 'i2': miINT16,
+ 'i4': miINT32,
+ 'u1': miUINT8,
+ 'u4': miUINT32,
+ 'u2': miUINT16,
+ 'S1': miUINT8,
+ 'U1': miUTF16,
+ }
+
+
+np_to_mxtypes = {
+ 'f8': mxDOUBLE_CLASS,
+ 'c32': mxDOUBLE_CLASS,
+ 'c24': mxDOUBLE_CLASS,
+ 'c16': mxDOUBLE_CLASS,
+ 'f4': mxSINGLE_CLASS,
+ 'c8': mxSINGLE_CLASS,
+ 'i4': mxINT32_CLASS,
+ 'i2': mxINT16_CLASS,
+ 'u2': mxUINT16_CLASS,
+ 'u1': mxUINT8_CLASS,
+ 'S1': mxUINT8_CLASS,
+ }
+
+
+
+''' Before release v7.1 (release 14) matlab (TM) used the system
+default character encoding scheme padded out to 16-bits. Release 14
+and later use Unicode. When saving character data, R14 checks if it
+can be encoded in 7-bit ascii, and saves in that format if so.'''
+
+codecs_template = {
+ miUTF8: {'codec': 'utf_8', 'width': 1},
+ miUTF16: {'codec': 'utf_16', 'width': 2},
+ miUTF32: {'codec': 'utf_32','width': 4},
+ }
+
+miUINT16_codec = sys.getdefaultencoding()
+
+mx_numbers = (
+ mxDOUBLE_CLASS,
+ mxSINGLE_CLASS,
+ mxINT8_CLASS,
+ mxUINT8_CLASS,
+ mxINT16_CLASS,
+ mxUINT16_CLASS,
+ mxINT32_CLASS,
+ mxUINT32_CLASS,
+ )
+
+class mat_struct(object):
+ ''' Placeholder for holding read data from structs '''
+ pass
+
+class mat_obj(object):
+ ''' Placeholder for holding read data from objects '''
+ pass
+
+class Mat5ArrayReader(MatArrayReader):
+ ''' Class to get Mat5 arrays
+
+ Provides element reader functions, header reader, matrix reader
+ factory function
+ '''
+
+ def __init__(self, mat_stream, dtypes, processor_func, codecs, class_dtypes):
+ super(Mat5ArrayReader, self).__init__(mat_stream,
+ dtypes,
+ processor_func,
+ )
+ self.codecs = codecs
+ self.class_dtypes = class_dtypes
+
+ def read_element(self, copy=True):
+ raw_tag = self.mat_stream.read(8)
+ tag = N.ndarray(shape=(),
+ dtype=self.dtypes['tag_full'],
+ buffer = raw_tag)
+ mdtype = tag['mdtype'].item()
+ byte_count = mdtype >> 16
+ if byte_count: # small data element format
+ if byte_count > 4:
+ raise ValueError, 'Too many bytes for sde format'
+ mdtype = mdtype & 0xFFFF
+ dt = self.dtypes[mdtype]
+ el_count = byte_count / dt.itemsize
+ return N.ndarray(shape=(el_count,),
+ dtype=dt,
+ buffer=raw_tag[4:])
+ byte_count = tag['byte_count'].item()
+ if mdtype == miMATRIX:
+ return self.current_getter(byte_count).get_array()
+ if mdtype in self.codecs: # encoded char data
+ raw_str = self.mat_stream.read(byte_count)
+ codec = self.codecs[mdtype]
+ if not codec:
+ raise TypeError, 'Do not support encoding %d' % mdtype
+ el = raw_str.decode(codec)
+ else: # numeric data
+ dt = self.dtypes[mdtype]
+ el_count = byte_count / dt.itemsize
+ el = N.ndarray(shape=(el_count,),
+ dtype=dt,
+ buffer=self.mat_stream.read(byte_count))
+ if copy:
+ el = el.copy()
+ mod8 = byte_count % 8
+ if mod8:
+ self.mat_stream.seek(8 - mod8, 1)
+ return el
+
+ def matrix_getter_factory(self):
+ ''' Returns reader for next matrix at top level '''
+ tag = self.read_dtype(self.dtypes['tag_full'])
+ mdtype = tag['mdtype'].item()
+ byte_count = tag['byte_count'].item()
+ next_pos = self.mat_stream.tell() + byte_count
+ if mdtype == miCOMPRESSED:
+ getter = Mat5ZArrayReader(self, byte_count).matrix_getter_factory()
+ elif not mdtype == miMATRIX:
+ raise TypeError, \
+ 'Expecting miMATRIX type here, got %d' % mdtype
+ else:
+ getter = self.current_getter(byte_count)
+ getter.next_position = next_pos
+ return getter
+
+ def current_getter(self, byte_count):
+ ''' Return matrix getter for current stream position
+
+ Returns matrix getters at top level and sub levels
+ '''
+ if not byte_count: # an empty miMATRIX can contain no bytes
+ return Mat5EmptyMatrixGetter(self)
+ af = self.read_dtype(self.dtypes['array_flags'])
+ header = {}
+ flags_class = af['flags_class']
+ mc = flags_class & 0xFF
+ header['mclass'] = mc
+ header['is_logical'] = flags_class >> 9 & 1
+ header['is_global'] = flags_class >> 10 & 1
+ header['is_complex'] = flags_class >> 11 & 1
+ header['nzmax'] = af['nzmax']
+ header['dims'] = self.read_element()
+ header['name'] = self.read_element().tostring()
+ if mc in mx_numbers:
+ return Mat5NumericMatrixGetter(self, header)
+ if mc == mxSPARSE_CLASS:
+ return Mat5SparseMatrixGetter(self, header)
+ if mc == mxCHAR_CLASS:
+ return Mat5CharMatrixGetter(self, header)
+ if mc == mxCELL_CLASS:
+ return Mat5CellMatrixGetter(self, header)
+ if mc == mxSTRUCT_CLASS:
+ return Mat5StructMatrixGetter(self, header)
+ if mc == mxOBJECT_CLASS:
+ return Mat5ObjectMatrixGetter(self, header)
+ raise TypeError, 'No reader for class code %s' % mc
+
+
+class Mat5ZArrayReader(Mat5ArrayReader):
+ ''' Getter for compressed arrays
+
+ Reads and uncompresses gzipped stream on init, providing wrapper
+ for this new sub-stream.
+ '''
+ def __init__(self, array_reader, byte_count):
+ '''Reads and uncompresses gzipped stream'''
+ data = array_reader.mat_stream.read(byte_count)
+ super(Mat5ZArrayReader, self).__init__(
+ StringIO(zlib.decompress(data)),
+ array_reader.dtypes,
+ array_reader.processor_func,
+ array_reader.codecs,
+ array_reader.class_dtypes)
+
+
+class Mat5MatrixGetter(MatMatrixGetter):
+ ''' Base class for getting Mat5 matrices
+
+ Gets current read information from passed array_reader
+ '''
+
+ def __init__(self, array_reader, header):
+ super(Mat5MatrixGetter, self).__init__(array_reader, header)
+ self.class_dtypes = array_reader.class_dtypes
+ self.codecs = array_reader.codecs
+ self.is_global = header['is_global']
+ self.mat_dtype = None
+
+ def read_element(self, *args, **kwargs):
+ return self.array_reader.read_element(*args, **kwargs)
+
+
+class Mat5EmptyMatrixGetter(Mat5MatrixGetter):
+ ''' Dummy class to return empty array for empty matrix
+ '''
+ def __init__(self, array_reader):
+ self.array_reader = array_reader
+ self.mat_stream = array_reader.mat_stream
+ self.data_position = self.mat_stream.tell()
+ self.header = {}
+ self.is_global = False
+ self.mat_dtype = 'f8'
+
+ def get_raw_array(self):
+ return N.array([[]])
+
+
+class Mat5NumericMatrixGetter(Mat5MatrixGetter):
+
+ def __init__(self, array_reader, header):
+ super(Mat5NumericMatrixGetter, self).__init__(array_reader, header)
+ if header['is_logical']:
+ self.mat_dtype = N.dtype('bool')
+ else:
+ self.mat_dtype = self.class_dtypes[header['mclass']]
+
+ def get_raw_array(self):
+ if self.header['is_complex']:
+ # avoid array copy to save memory
+ res = self.read_element(copy=False)
+ res_j = self.read_element(copy=False)
+ res = res + (res_j * 1j)
+ else:
+ res = self.read_element()
+ return N.ndarray(shape=self.header['dims'],
+ dtype=res.dtype,
+ buffer=res,
+ order='F')
+
+
+class Mat5SparseMatrixGetter(Mat5MatrixGetter):
+ def get_raw_array(self):
+ rowind = self.read_element()
+ indptr = self.read_element()
+ if self.header['is_complex']:
+ # avoid array copy to save memory
+ data = self.read_element(copy=False)
+ data_j = self.read_element(copy=False)
+ data = data + (data_j * 1j)
+ else:
+ data = self.read_element()
+ ''' From the matlab (TM) API documentation, last found here:
+ http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_external/
+ rowind are simply the row indices for all the (res) non-zero
+ entries in the sparse array. rowind has nzmax entries, so
+ may well have more entries than len(res), the actual number
+ of non-zero entries, but rowind[len(res):] can be discarded
+ and should be 0. indptr has length (number of columns + 1),
+ and is such that, if D = diff(colind), D[j] gives the number
+ of non-zero entries in column j. Because rowind values are
+ stored in column order, this gives the column corresponding to
+ each rowind
+ '''
+ if have_sparse:
+ dims = self.header['dims']
+ return scipy.sparse.csc_matrix((data,rowind,indptr), dims)
+ else:
+ return (dims, data, rowind, indptr)
+
+
+class Mat5CharMatrixGetter(Mat5MatrixGetter):
+ def get_raw_array(self):
+ res = self.read_element()
+ # Convert non-string types to unicode
+ if isinstance(res, N.ndarray):
+ if res.dtype.type == N.uint16:
+ codec = miUINT16_codec
+ if self.codecs['uint16_len'] == 1:
+ res = res.astype(N.uint8)
+ elif res.dtype.type in (N.uint8, N.int8):
+ codec = 'ascii'
+ else:
+ raise TypeError, 'Did not expect type %s' % res.dtype
+ res = res.tostring().decode(codec)
+ return N.ndarray(shape=self.header['dims'],
+ dtype=N.dtype('U1'),
+ buffer=N.array(res),
+ order='F').copy()
+
+
+class Mat5CellMatrixGetter(Mat5MatrixGetter):
+ def get_raw_array(self):
+ # Account for fortran indexing of cells
+ tupdims = tuple(self.header['dims'][::-1])
+ length = N.product(tupdims)
+ result = N.empty(length, dtype=object)
+ for i in range(length):
+ result[i] = self.get_item()
+ return result.reshape(tupdims).T
+
+ def get_item(self):
+ return self.read_element()
+
+
+class Mat5StructMatrixGetter(Mat5CellMatrixGetter):
+ def __init__(self, *args, **kwargs):
+ super(Mat5StructMatrixGetter, self).__init__(*args, **kwargs)
+ self.obj_template = mat_struct()
+
+ def get_raw_array(self):
+ namelength = self.read_element()[0]
+ # get field names
+ names = self.read_element()
+ splitnames = [names[i:i+namelength] for i in \
+ xrange(0,len(names),namelength)]
+ self.obj_template._fieldnames = [x.tostring().strip('\x00')
+ for x in splitnames]
+ return super(Mat5StructMatrixGetter, self).get_raw_array()
+
+ def get_item(self):
+ item = pycopy(self.obj_template)
+ for element in item._fieldnames:
+ item.__dict__[element] = self.read_element()
+ return item
+
+
+class Mat5ObjectMatrixGetter(Mat5StructMatrixGetter):
+ def __init__(self, *args, **kwargs):
+ super(Mat5StructMatrixGetter, self).__init__(*args, **kwargs)
+ self.obj_template = mat_obj()
+
+ def get_raw_array(self):
+ self.obj_template._classname = self.read_element().tostring()
+ return super(Mat5ObjectMatrixGetter, self).get_raw_array()
+
+
+class MatFile5Reader(MatFileReader):
+ ''' Reader for Mat 5 mat files
+
+ Adds the following attribute to base class
+
+ uint16_codec - char codec to use for uint16 char arrays
+ (defaults to system default codec)
+ '''
+
+ def __init__(self,
+ mat_stream,
+ byte_order=None,
+ mat_dtype=False,
+ squeeze_me=True,
+ chars_as_strings=True,
+ matlab_compatible=False,
+ uint16_codec=None
+ ):
+ self.codecs = {}
+ self._array_reader = Mat5ArrayReader(
+ mat_stream,
+ None,
+ None,
+ None,
+ None,
+ )
+ super(MatFile5Reader, self).__init__(
+ mat_stream,
+ byte_order,
+ mat_dtype,
+ squeeze_me,
+ chars_as_strings,
+ matlab_compatible,
+ )
+ self._array_reader.processor_func = self.processor_func
+ self.uint16_codec = uint16_codec
+
+ def get_uint16_codec(self):
+ return self._uint16_codec
+ def set_uint16_codec(self, uint16_codec):
+ if not uint16_codec:
+ uint16_codec = sys.getdefaultencoding()
+ # Set length of miUINT16 char encoding
+ self.codecs['uint16_len'] = len(" ".encode(uint16_codec)) \
+ - len(" ".encode(uint16_codec))
+ self.codecs['uint16_codec'] = uint16_codec
+ self._array_reader.codecs = self.codecs
+ self._uint16_codec = uint16_codec
+ uint16_codec = property(get_uint16_codec,
+ set_uint16_codec,
+ None,
+ 'get/set uint16_codec')
+
+ def set_dtypes(self):
+ ''' Set dtypes and codecs '''
+ self.dtypes = self.convert_dtypes(mdtypes_template)
+ self.class_dtypes = self.convert_dtypes(mclass_dtypes_template)
+ codecs = {}
+ postfix = self.order_code == '<' and '_le' or '_be'
+ for k, v in codecs_template.items():
+ codec = v['codec']
+ try:
+ " ".encode(codec)
+ except LookupError:
+ codecs[k] = None
+ continue
+ if v['width'] > 1:
+ codec += postfix
+ codecs[k] = codec
+ self.codecs.update(codecs)
+ self.update_array_reader()
+
+ def update_array_reader(self):
+ self._array_reader.codecs = self.codecs
+ self._array_reader.dtypes = self.dtypes
+ self._array_reader.class_dtypes = self.class_dtypes
+
+ def matrix_getter_factory(self):
+ return self._array_reader.matrix_getter_factory()
+
+ def guess_byte_order(self):
+ self.mat_stream.seek(126)
+ mi = self.mat_stream.read(2)
+ self.mat_stream.seek(0)
+ return mi == 'IM' and '<' or '>'
+
+ def file_header(self):
+ ''' Read in mat 5 file header '''
+ hdict = {}
+ hdr = self.read_dtype(self.dtypes['file_header'])
+ hdict['__header__'] = hdr['description'].item().strip(' \t\n\000')
+ v_major = hdr['version'] >> 8
+ v_minor = hdr['version'] & 0xFF
+ hdict['__version__'] = '%d.%d' % (v_major, v_minor)
+ return hdict
+
+ def format_looks_right(self):
+ # Mat4 files have a zero somewhere in first 4 bytes
+ self.mat_stream.seek(0)
+ mopt_bytes = N.ndarray(shape=(4,),
+ dtype=N.uint8,
+ buffer = self.mat_stream.read(4))
+ self.mat_stream.seek(0)
+ return 0 not in mopt_bytes
+
+
+class Mat5MatrixWriter(MatStreamWriter):
+
+ mat_tag = N.zeros((), mdtypes_template['tag_full'])
+ mat_tag['mdtype'] = miMATRIX
+
+ def __init__(self, file_stream, arr, name, is_global=False):
+ super(Mat5MatrixWriter, self).__init__(file_stream, arr, name)
+ self.is_global = is_global
+
+ def write_dtype(self, arr):
+ self.file_stream.write(arr.tostring())
+
+ def write_element(self, arr, mdtype=None):
+ # write tag, data
+ tag = N.zeros((), mdtypes_template['tag_full'])
+ if mdtype is None:
+ tag['mdtype'] = np_to_mtypes[arr.dtype.str[1:]]
+ else:
+ tag['mdtype'] = mdtype
+ tag['byte_count'] = arr.size*arr.itemsize
+ self.write_dtype(tag)
+ self.write_bytes(arr)
+ # do 8 byte padding if needed
+ if tag['byte_count']%8 != 0:
+ pad = (1+tag['byte_count']//8)*8 - tag['byte_count']
+ self.write_bytes(N.zeros((pad,),dtype='u1'))
+
+ def write_header(self, mclass,
+ is_global=False,
+ is_complex=False,
+ is_logical=False,
+ nzmax=0):
+ ''' Write header for given data options
+ mclass - mat5 matrix class
+ is_global - True if matrix is global
+ is_complex - True is matrix is complex
+ is_logical - True if matrix is logical
+ nzmax - max non zero elements for sparse arrays
+ '''
+ self._mat_tag_pos = self.file_stream.tell()
+ self.write_dtype(self.mat_tag)
+ # write array flags (complex, global, logical, class, nzmax)
+ af = N.zeros((), mdtypes_template['array_flags'])
+ af['data_type'] = miUINT32
+ af['byte_count'] = 8
+ flags = is_complex << 3 | is_global << 2 | is_logical << 1
+ af['flags_class'] = mclass | flags << 8
+ af['nzmax'] = nzmax
+ self.write_dtype(af)
+ # write array shape
+ self.arr=N.atleast_2d(self.arr)
+ self.write_element(N.array(self.arr.shape, dtype='i4'))
+ # write name
+ self.write_element(N.ndarray(shape=len(self.name), dtype='S1', buffer=self.name))
+
+ def update_matrix_tag(self):
+ curr_pos = self.file_stream.tell()
+ self.file_stream.seek(self._mat_tag_pos)
+ self.mat_tag['byte_count'] = curr_pos - self._mat_tag_pos - 8
+ self.write_dtype(self.mat_tag)
+ self.file_stream.seek(curr_pos)
+
+ def write(self):
+ assert False, 'Not implemented'
+
+
+class Mat5NumericWriter(Mat5MatrixWriter):
+
+ def write(self):
+ imagf = self.arr.dtype.kind == 'c'
+ try:
+ mclass = np_to_mxtypes[self.arr.dtype.str[1:]]
+ except KeyError:
+ if imagf:
+ self.arr = self.arr.astype('c128')
+ else:
+ self.arr = self.arr.astype('f8')
+ mclass = mxDOUBLE_CLASS
+ self.write_header(mclass=mclass,is_complex=imagf)
+ if imagf:
+ self.write_element(self.arr.real)
+ self.write_element(self.arr.imag)
+ else:
+ self.write_element(self.arr)
+ self.update_matrix_tag()
+
+class Mat5CharWriter(Mat5MatrixWriter):
+ codec='ascii'
+ def write(self):
+ self.arr_to_chars()
+ self.write_header(mclass=mxCHAR_CLASS)
+ if self.arr.dtype.kind == 'U':
+ # Recode unicode using self.codec
+ n_chars = N.product(self.arr.shape)
+ st_arr = N.ndarray(shape=(),
+ dtype=self.arr_dtype_number(n_chars),
+ buffer=self.arr)
+ st = st_arr.item().encode(self.codec)
+ self.arr = N.ndarray(shape=(len(st)), dtype='u1', buffer=st)
+ self.write_element(self.arr,mdtype=miUTF8)
+ self.update_matrix_tag()
+
+class Mat5UniCharWriter(Mat5CharWriter):
+ codec='UTF8'
+
+
+class Mat5SparseWriter(Mat5MatrixWriter):
+
+ def write(self):
+ ''' Sparse matrices are 2D
+ See docstring for Mat5SparseGetter
+ '''
+ imagf = self.arr.dtype.kind == 'c'
+ N = self.arr.nnz
+ ijd = N.zeros((N+1, 3+imagf), dtype='f8')
+ for i in range(N):
+ ijd[i,0], ijd[i,1] = self.arr.rowcol(i)
+ ijd[:-1,0:2] += 1 # 1 based indexing
+ if imagf:
+ ijd[:-1,2] = self.arr.data.real
+ ijd[:-1,3] = self.arr.data.imag
+ else:
+ ijd[:-1,2] = self.arr.data
+ ijd[-1,0:2] = self.arr.shape
+ self.write_header(P=miDOUBLE,
+ T=mxSPARSE_CLASS,
+ dims=ijd.shape)
+ self.write_bytes(ijd)
+
+
+class Mat5WriterGetter(object):
+ ''' Wraps stream and options, provides methods for getting Writer objects '''
+ def __init__(self, stream, unicode_strings):
+ self.stream = stream
+ self.unicode_strings = unicode_strings
+
+ def rewind(self):
+ self.stream.seek(0)
+
+ def matrix_writer_factory(self, arr, name, is_global=False):
+ ''' Factory function to return matrix writer given variable to write
+ stream - file or file-like stream to write to
+ arr - array to write
+ name - name in matlab (TM) workspace
+ '''
+ if have_sparse:
+ if scipy.sparse.issparse(arr):
+ return Mat5SparseWriter(self.stream, arr, name, is_global)
+ arr = N.array(arr)
+ if arr.dtype.hasobject:
+ types, arr_type = self.classify_mobjects(arr)
+ if arr_type == 'c':
+ return Mat5CellWriter(self.stream, arr, name, is_global, types)
+ elif arr_type == 's':
+ return Mat5StructWriter(self.stream, arr, name, is_global)
+ elif arr_type == 'o':
+ return Mat5ObjectWriter(self.stream, arr, name, is_global)
+ if arr.dtype.kind in ('U', 'S'):
+ if self.unicode_strings:
+ return Mat5UniCharWriter(self.stream, arr, name, is_global)
+ else:
+ return Mat5CharWriter(self.stream, arr, name, is_global)
+ else:
+ return Mat5NumericWriter(self.stream, arr, name, is_global)
+
+ def classify_mobjects(self, objarr):
+ ''' Function to classify objects passed for writing
+ returns
+ types - S1 array of same shape as objarr with codes for each object
+ i - invalid object
+ a - ndarray
+ s - matlab struct
+ o - matlab object
+ arr_type - one of
+ c - cell array
+ s - struct array
+ o - object array
+ '''
+ n = objarr.size
+ types = N.empty((n,), dtype='S1')
+ types[:] = 'i'
+ type_set = set()
+ flato = objarr.flat
+ for i in range(n):
+ obj = flato[i]
+ if isinstance(obj, N.ndarray):
+ types[i] = 'a'
+ continue
+ try:
+ fns = tuple(obj._fieldnames)
+ except AttributeError:
+ continue
+ try:
+ cn = obj._classname
+ except AttributeError:
+ types[i] = 's'
+ type_set.add(fns)
+ continue
+ types[i] = 'o'
+ type_set.add((cn, fns))
+ arr_type = 'c'
+ if len(set(types))==1 and len(type_set) == 1:
+ arr_type = types[0]
+ return types.reshape(objarr.shape), arr_type
+
+
+class MatFile5Writer(MatFileWriter):
+ ''' Class for writing mat5 files '''
+ def __init__(self, file_stream,
+ do_compression=False,
+ unicode_strings=False,
+ global_vars=None):
+ super(MatFile5Writer, self).__init__(file_stream)
+ self.do_compression = do_compression
+ if global_vars:
+ self.global_vars = global_vars
+ else:
+ self.global_vars = []
+ self.writer_getter = Mat5WriterGetter(
+ StringIO(),
+ unicode_strings)
+ # write header
+ import os, time
+ hdr = N.zeros((), mdtypes_template['file_header'])
+ hdr['description']='MATLAB 5.0 MAT-file Platform: %s, Created on: %s' % (
+ os.name,time.asctime())
+ hdr['version']= 0x0100
+ hdr['endian_test']=N.ndarray(shape=(),dtype='S2',buffer=N.uint16(0x4d49))
+ file_stream.write(hdr.tostring())
+
+ def get_unicode_strings(self):
+ return self.write_getter.unicode_strings
+ def set_unicode_strings(self, unicode_strings):
+ self.writer_getter.unicode_strings = unicode_strings
+ unicode_strings = property(get_unicode_strings,
+ set_unicode_strings,
+ None,
+ 'get/set unicode strings property')
+
+ def put_variables(self, mdict):
+ for name, var in mdict.items():
+ is_global = name in self.global_vars
+ self.writer_getter.rewind()
+ self.writer_getter.matrix_writer_factory(
+ var,
+ name,
+ is_global,
+ ).write()
+ stream = self.writer_getter.stream
+ if self.do_compression:
+ str = zlib.compress(stream.getvalue(stream.tell()))
+ tag = N.empty((), mdtypes_template['tag_full'])
+ tag['mdtype'] = miCOMPRESSED
+ tag['byte_count'] = len(str)
+ self.file_stream.write(tag.tostring() + str)
+ else:
+ self.file_stream.write(stream.getvalue(stream.tell()))
Copied: branches/io_new/matlab/miobase.py (from rev 3657, branches/io_new/miobase.py)
Deleted: branches/io_new/mio.py
===================================================================
--- branches/io_new/mio.py 2007-12-14 23:31:02 UTC (rev 3658)
+++ branches/io_new/mio.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -1,133 +0,0 @@
-# Authors: Travis Oliphant, Matthew Brett
-
-"""
-Module for reading and writing matlab (TM) .mat files
-"""
-
-import os
-import sys
-
-from scipy.io.mio4 import MatFile4Reader, MatFile4Writer
-from scipy.io.mio5 import MatFile5Reader, MatFile5Writer
-
-__all__ = ['find_mat_file', 'mat_reader_factory', 'loadmat', 'savemat']
-
-def find_mat_file(file_name, appendmat=True):
- ''' Try to find .mat file on system path
-
- file_name - file name string
- append_mat - If True, and file_name does not end in '.mat', appends it
- '''
- if appendmat and file_name[-4:] == ".mat":
- file_name = file_name[:-4]
- if os.sep in file_name:
- full_name = file_name
- if appendmat:
- full_name = file_name + ".mat"
- else:
- full_name = None
- junk, file_name = os.path.split(file_name)
- for path in [os.curdir] + list(sys.path):
- test_name = os.path.join(path, file_name)
- if appendmat:
- test_name += ".mat"
- try:
- fid = open(test_name,'rb')
- fid.close()
- full_name = test_name
- break
- except IOError:
- pass
- return full_name
-
-def mat_reader_factory(file_name, appendmat=True, **kwargs):
- """Create reader for matlab (TM) .mat format files
-
- See docstring for loadmat for input options
- """
- if isinstance(file_name, basestring):
- full_name = find_mat_file(file_name, appendmat)
- if full_name is None:
- raise IOError, "%s not found on the path." % file_name
- byte_stream = open(full_name, 'rb')
- else:
- try:
- file_name.read(0)
- except AttributeError:
- raise IOError, 'Reader needs file name or open file-like object'
- byte_stream = file_name
-
- MR = MatFile4Reader(byte_stream, **kwargs)
- if MR.format_looks_right():
- return MR
- return MatFile5Reader(byte_stream, **kwargs)
-
-def loadmat(file_name, mdict=None, appendmat=True, basename='raw', **kwargs):
- ''' Load Matlab(tm) file
-
- file_name - Name of the mat file
- (do not need .mat extension if appendmat==True)
- If name not a full path name, search for the file on
- the sys.path list and use the first one found (the
- current directory is searched first).
- Can also pass open file-like object
- m_dict - optional dictionary in which to insert matfile variables
- appendmat - True to append the .mat extension to the end of the
- given filename, if not already present
- base_name - base name for unnamed variables (unused in code)
- byte_order - byte order ('native', 'little', 'BIG')
- in ('native', '=')
- or in ('little', '<')
- or in ('BIG', '>')
- mat_dtype - return arrays in same dtype as loaded into matlab
- (instead of the dtype with which they are saved)
- squeeze_me - whether to squeeze matrix dimensions or not
- chars_as_strings - whether to convert char arrays to string arrays
- mat_dtype - return matrices with datatype that matlab would load as
- (rather than in the datatype matlab saves as)
- matlab_compatible - returns matrices as would be loaded by matlab
- (implies squeeze_me=False, chars_as_strings=False,
- mat_dtype=True)
-
- v4 (Level 1.0), v6 and v7.1 matfiles are supported.
-
- '''
- MR = mat_reader_factory(file_name, appendmat, **kwargs)
- matfile_dict = MR.get_variables()
- if mdict is not None:
- mdict.update(matfile_dict)
- else:
- mdict = matfile_dict
- return mdict
-
-def savemat(file_name, mdict, appendmat=True, format='4'):
- """Save a dictionary of names and arrays into the MATLAB-style .mat file.
-
- This saves the arrayobjects in the given dictionary to a matlab
- style .mat file.
-
- appendmat - if true, appends '.mat' extension to filename, if not present
- format - '4' for matlab 4 mat files, '5' for matlab 5 onwards
- """
- file_is_string = isinstance(file_name, basestring)
- if file_is_string:
- if appendmat and file_name[-4:] != ".mat":
- file_name = file_name + ".mat"
- file_stream = open(file_name, 'wb')
- else:
- try:
- file_name.write('')
- except AttributeError:
- raise IOError, 'Writer needs file name or writeable '\
- 'file-like object'
- file_stream = file_name
-
- if format == '4':
- MW = MatFile4Writer(file_stream)
- elif format == '5':
- MW = MatFile5Writer(file_stream)
- else:
- raise ValueError, 'Format should be 4 or 5'
- MW.put_variables(mdict)
- if file_is_string:
- file_stream.close()
Deleted: branches/io_new/mio4.py
===================================================================
--- branches/io_new/mio4.py 2007-12-14 23:31:02 UTC (rev 3658)
+++ branches/io_new/mio4.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -1,345 +0,0 @@
-''' Classes for read / write of matlab (TM) 4 files
-'''
-
-import numpy as N
-
-from scipy.io.miobase import *
-
-miDOUBLE = 0
-miSINGLE = 1
-miINT32 = 2
-miINT16 = 3
-miUINT16 = 4
-miUINT8 = 5
-
-mdtypes_template = {
- miDOUBLE: 'f8',
- miSINGLE: 'f4',
- miINT32: 'i4',
- miINT16: 'i2',
- miUINT16: 'u2',
- miUINT8: 'u1',
- 'header': [('mopt', 'i4'),
- ('mrows', 'i4'),
- ('ncols', 'i4'),
- ('imagf', 'i4'),
- ('namlen', 'i4')],
- 'U1': 'U1',
- }
-
-np_to_mtypes = {
- 'f8': miDOUBLE,
- 'c32': miDOUBLE,
- 'c24': miDOUBLE,
- 'c16': miDOUBLE,
- 'f4': miSINGLE,
- 'c8': miSINGLE,
- 'i4': miINT32,
- 'i2': miINT16,
- 'u2': miUINT16,
- 'u1': miUINT8,
- 'S1': miUINT8,
- }
-
-# matrix classes
-mxFULL_CLASS = 0
-mxCHAR_CLASS = 1
-mxSPARSE_CLASS = 2
-
-order_codes = {
- 0: '<',
- 1: '>',
- 2: 'VAX D-float', #!
- 3: 'VAX G-float',
- 4: 'Cray', #!!
- }
-
-
-class Mat4ArrayReader(MatArrayReader):
- ''' Class for reading Mat4 arrays
- '''
-
- def matrix_getter_factory(self):
- ''' Read header, return matrix getter '''
- data = self.read_dtype(self.dtypes['header'])
- header = {}
- header['name'] = self.read_ztstring(data['namlen'])
- if data['mopt'] < 0 or data['mopt'] > 5000:
- ValueError, 'Mat 4 mopt wrong format, byteswapping problem?'
- M,rest = divmod(data['mopt'], 1000)
- O,rest = divmod(rest,100)
- P,rest = divmod(rest,10)
- T = rest
- if O != 0:
- raise ValueError, 'O in MOPT integer should be 0, wrong format?'
- header['dtype'] = self.dtypes[P]
- header['mclass'] = T
- header['dims'] = (data['mrows'], data['ncols'])
- header['is_complex'] = data['imagf'] == 1
- remaining_bytes = header['dtype'].itemsize * N.product(header['dims'])
- if header['is_complex'] and not header['mclass'] == mxSPARSE_CLASS:
- remaining_bytes *= 2
- next_pos = self.mat_stream.tell() + remaining_bytes
- if T == mxFULL_CLASS:
- getter = Mat4FullGetter(self, header)
- elif T == mxCHAR_CLASS:
- getter = Mat4CharGetter(self, header)
- elif T == mxSPARSE_CLASS:
- getter = Mat4SparseGetter(self, header)
- else:
- raise TypeError, 'No reader for class code %s' % T
- getter.next_position = next_pos
- return getter
-
-
-class Mat4MatrixGetter(MatMatrixGetter):
-
- # Mat4 variables never global or logical
- is_global = False
- is_logical = False
-
- def read_array(self, copy=True):
- ''' Mat4 read array always uses header dtype and dims
- copy - copies array if True
- (buffer is usually read only)
- a_dtype is assumed to be correct endianness
- '''
- dt = self.header['dtype']
- dims = self.header['dims']
- num_bytes = dt.itemsize
- for d in dims:
- num_bytes *= d
- arr = N.ndarray(shape=dims,
- dtype=dt,
- buffer=self.mat_stream.read(num_bytes),
- order='F')
- if copy:
- arr = arr.copy()
- return arr
-
-
-class Mat4FullGetter(Mat4MatrixGetter):
- def __init__(self, array_reader, header):
- super(Mat4FullGetter, self).__init__(array_reader, header)
- if header['is_complex']:
- self.mat_dtype = N.dtype(N.complex128)
- else:
- self.mat_dtype = N.dtype(N.float64)
-
- def get_raw_array(self):
- if self.header['is_complex']:
- # avoid array copy to save memory
- res = self.read_array(copy=False)
- res_j = self.read_array(copy=False)
- return res + (res_j * 1j)
- return self.read_array()
-
-
-class Mat4CharGetter(Mat4MatrixGetter):
- def get_raw_array(self):
- arr = self.read_array().astype(N.uint8)
- # ascii to unicode
- S = arr.tostring().decode('ascii')
- return N.ndarray(shape=self.header['dims'],
- dtype=N.dtype('U1'),
- buffer = N.array(S)).copy()
-
-
-class Mat4SparseGetter(Mat4MatrixGetter):
- ''' Read sparse matrix type
-
- Matlab (TM) 4 real sparse arrays are saved in a N+1 by 3 array
- format, where N is the number of non-zero values. Column 1 values
- [0:N] are the (1-based) row indices of the each non-zero value,
- column 2 [0:N] are the column indices, column 3 [0:N] are the
- (real) values. The last values [-1,0:2] of the rows, column
- indices are shape[0] and shape[1] respectively of the output
- matrix. The last value for the values column is a padding 0. mrows
- and ncols values from the header give the shape of the stored
- matrix, here [N+1, 3]. Complex data is saved as a 4 column
- matrix, where the fourth column contains the imaginary component;
- the last value is again 0. Complex sparse data do _not_ have the
- header imagf field set to True; the fact that the data are complex
- is only detectable because there are 4 storage columns
- '''
- def get_raw_array(self):
- res = self.read_array()
- tmp = res[:-1,:]
- dims = res[-1,0:2]
- I = N.ascontiguousarray(tmp[:,0],dtype='intc') #fixes byte order also
- J = N.ascontiguousarray(tmp[:,1],dtype='intc')
- I -= 1 # for 1-based indexing
- J -= 1
- if res.shape[1] == 3:
- V = N.ascontiguousarray(tmp[:,2],dtype='float')
- else:
- V = N.ascontiguousarray(tmp[:,2],dtype='complex')
- V.imag = tmp[:,3]
- if have_sparse:
- return scipy.sparse.coo_matrix((V,(I,J)), dims)
- return (dims, I, J, V)
-
-
-class MatFile4Reader(MatFileReader):
- ''' Reader for Mat4 files '''
- def __init__(self, mat_stream, *args, **kwargs):
- self._array_reader = Mat4ArrayReader(
- mat_stream,
- None,
- None,
- )
- super(MatFile4Reader, self).__init__(mat_stream, *args, **kwargs)
- self._array_reader.processor_func = self.processor_func
-
- def set_dtypes(self):
- self.dtypes = self.convert_dtypes(mdtypes_template)
- self._array_reader.dtypes = self.dtypes
-
- def matrix_getter_factory(self):
- return self._array_reader.matrix_getter_factory()
-
- def format_looks_right(self):
- # Mat4 files have a zero somewhere in first 4 bytes
- self.mat_stream.seek(0)
- mopt_bytes = N.ndarray(shape=(4,),
- dtype=N.uint8,
- buffer = self.mat_stream.read(4))
- self.mat_stream.seek(0)
- return 0 in mopt_bytes
-
- def guess_byte_order(self):
- self.mat_stream.seek(0)
- mopt = self.read_dtype(N.dtype('i4'))
- self.mat_stream.seek(0)
- if mopt < 0 or mopt > 5000:
- return ByteOrder.swapped_code
- return ByteOrder.native_code
-
-
-class Mat4MatrixWriter(MatStreamWriter):
-
- def write_header(self, P=0, T=0, imagf=0, dims=None):
- ''' Write header for given data options
- P - mat4 data type
- T - mat4 matrix class
- imagf - complex flag
- dims - matrix dimensions
- '''
- if dims is None:
- dims = self.arr.shape
- header = N.empty((), mdtypes_template['header'])
- M = not ByteOrder.little_endian
- O = 0
- header['mopt'] = (M * 1000 +
- O * 100 +
- P * 10 +
- T)
- header['mrows'] = dims[0]
- header['ncols'] = dims[1]
- header['imagf'] = imagf
- header['namlen'] = len(self.name) + 1
- self.write_bytes(header)
- self.write_string(self.name + '\0')
-
- def arr_to_2d(self):
- self.arr = N.atleast_2d(self.arr)
- dims = self.arr.shape
- if len(dims) > 2:
- self.arr = self.arr.reshape(-1,dims[-1])
-
- def write(self):
- assert False, 'Not implemented'
-
-
-class Mat4NumericWriter(Mat4MatrixWriter):
-
- def write(self):
- self.arr_to_2d()
- imagf = self.arr.dtype.kind == 'c'
- try:
- P = np_to_mtypes[self.arr.dtype.str[1:]]
- except KeyError:
- if imagf:
- self.arr = self.arr.astype('c128')
- else:
- self.arr = self.arr.astype('f8')
- P = miDOUBLE
- self.write_header(P=P,
- T=mxFULL_CLASS,
- imagf=imagf)
- if imagf:
- self.write_bytes(self.arr.real)
- self.write_bytes(self.arr.imag)
- else:
- self.write_bytes(self.arr)
-
-
-class Mat4CharWriter(Mat4MatrixWriter):
-
- def write(self):
- self.arr_to_chars()
- self.arr_to_2d()
- dims = self.arr.shape
- self.write_header(P=miUINT8,
- T=mxCHAR_CLASS)
- if self.arr.dtype.kind == 'U':
- # Recode unicode to ascii
- n_chars = N.product(dims)
- st_arr = N.ndarray(shape=(),
- dtype=self.arr_dtype_number(n_chars),
- buffer=self.arr)
- st = st_arr.item().encode('ascii')
- self.arr = N.ndarray(shape=dims, dtype='S1', buffer=st)
- self.write_bytes(self.arr)
-
-
-class Mat4SparseWriter(Mat4MatrixWriter):
-
- def write(self):
- ''' Sparse matrices are 2D
- See docstring for Mat4SparseGetter
- '''
- imagf = self.arr.dtype.kind == 'c'
- nnz = self.arr.nnz
- ijd = N.zeros((nnz+1, 3+imagf), dtype='f8')
- for i in range(nnz):
- ijd[i,0], ijd[i,1] = self.arr.rowcol(i)
- ijd[:-1,0:2] += 1 # 1 based indexing
- if imagf:
- ijd[:-1,2] = self.arr.data.real
- ijd[:-1,3] = self.arr.data.imag
- else:
- ijd[:-1,2] = self.arr.data
- ijd[-1,0:2] = self.arr.shape
- self.write_header(P=miDOUBLE,
- T=mxSPARSE_CLASS,
- dims=ijd.shape)
- self.write_bytes(ijd)
-
-
-def matrix_writer_factory(stream, arr, name):
- ''' Factory function to return matrix writer given variable to write
- stream - file or file-like stream to write to
- arr - array to write
- name - name in matlab (TM) workspace
- '''
- if have_sparse:
- if scipy.sparse.issparse(arr):
- return Mat4SparseWriter(stream, arr, name)
- arr = N.array(arr)
- dtt = arr.dtype.type
- if dtt is N.object_:
- raise TypeError, 'Cannot save object arrays in Mat4'
- elif dtt is N.void:
- raise TypeError, 'Cannot save void type arrays'
- elif dtt in (N.unicode_, N.string_):
- return Mat4CharWriter(stream, arr, name)
- else:
- return Mat4NumericWriter(stream, arr, name)
-
-
-class MatFile4Writer(MatFileWriter):
-
- def put_variables(self, mdict):
- for name, var in mdict.items():
- matrix_writer_factory(self.file_stream, var, name).write()
Deleted: branches/io_new/mio5.py
===================================================================
--- branches/io_new/mio5.py 2007-12-14 23:31:02 UTC (rev 3658)
+++ branches/io_new/mio5.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -1,807 +0,0 @@
-''' Classes for read / write of matlab (TM) 5 files
-'''
-
-# Small fragments of current code adapted from matfile.py by Heiko
-# Henkelmann
-
-## Notice in matfile.py file
-
-# Copyright (c) 2003 Heiko Henkelmann
-
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-import zlib
-from copy import copy as pycopy
-from cStringIO import StringIO
-import numpy as N
-
-from scipy.io.miobase import *
-
-try: # Python 2.3 support
- from sets import Set as set
-except:
- pass
-
-miINT8 = 1
-miUINT8 = 2
-miINT16 = 3
-miUINT16 = 4
-miINT32 = 5
-miUINT32 = 6
-miSINGLE = 7
-miDOUBLE = 9
-miINT64 = 12
-miUINT64 = 13
-miMATRIX = 14
-miCOMPRESSED = 15
-miUTF8 = 16
-miUTF16 = 17
-miUTF32 = 18
-
-mxCELL_CLASS = 1
-mxSTRUCT_CLASS = 2
-mxOBJECT_CLASS = 3
-mxCHAR_CLASS = 4
-mxSPARSE_CLASS = 5
-mxDOUBLE_CLASS = 6
-mxSINGLE_CLASS = 7
-mxINT8_CLASS = 8
-mxUINT8_CLASS = 9
-mxINT16_CLASS = 10
-mxUINT16_CLASS = 11
-mxINT32_CLASS = 12
-mxUINT32_CLASS = 13
-
-mdtypes_template = {
- miINT8: 'i1',
- miUINT8: 'u1',
- miINT16: 'i2',
- miUINT16: 'u2',
- miINT32: 'i4',
- miUINT32: 'u4',
- miSINGLE: 'f4',
- miDOUBLE: 'f8',
- miINT64: 'i8',
- miUINT64: 'u8',
- miUTF8: 'u1',
- miUTF16: 'u2',
- miUTF32: 'u4',
- 'file_header': [('description', 'S116'),
- ('subsystem_offset', 'i8'),
- ('version', 'u2'),
- ('endian_test', 'S2')],
- 'tag_full': [('mdtype', 'u4'), ('byte_count', 'u4')],
- 'array_flags': [('data_type', 'u4'),
- ('byte_count', 'u4'),
- ('flags_class','u4'),
- ('nzmax', 'u4')],
- 'U1': 'U1',
- }
-
-mclass_dtypes_template = {
- mxINT8_CLASS: 'i1',
- mxUINT8_CLASS: 'u1',
- mxINT16_CLASS: 'i2',
- mxUINT16_CLASS: 'u2',
- mxINT32_CLASS: 'i4',
- mxUINT32_CLASS: 'u4',
- mxSINGLE_CLASS: 'f4',
- mxDOUBLE_CLASS: 'f8',
- }
-
-
-np_to_mtypes = {
- 'f8': miDOUBLE,
- 'c32': miDOUBLE,
- 'c24': miDOUBLE,
- 'c16': miDOUBLE,
- 'f4': miSINGLE,
- 'c8': miSINGLE,
- 'i1': miINT8,
- 'i2': miINT16,
- 'i4': miINT32,
- 'u1': miUINT8,
- 'u4': miUINT32,
- 'u2': miUINT16,
- 'S1': miUINT8,
- 'U1': miUTF16,
- }
-
-
-np_to_mxtypes = {
- 'f8': mxDOUBLE_CLASS,
- 'c32': mxDOUBLE_CLASS,
- 'c24': mxDOUBLE_CLASS,
- 'c16': mxDOUBLE_CLASS,
- 'f4': mxSINGLE_CLASS,
- 'c8': mxSINGLE_CLASS,
- 'i4': mxINT32_CLASS,
- 'i2': mxINT16_CLASS,
- 'u2': mxUINT16_CLASS,
- 'u1': mxUINT8_CLASS,
- 'S1': mxUINT8_CLASS,
- }
-
-
-
-''' Before release v7.1 (release 14) matlab (TM) used the system
-default character encoding scheme padded out to 16-bits. Release 14
-and later use Unicode. When saving character data, R14 checks if it
-can be encoded in 7-bit ascii, and saves in that format if so.'''
-
-codecs_template = {
- miUTF8: {'codec': 'utf_8', 'width': 1},
- miUTF16: {'codec': 'utf_16', 'width': 2},
- miUTF32: {'codec': 'utf_32','width': 4},
- }
-
-miUINT16_codec = sys.getdefaultencoding()
-
-mx_numbers = (
- mxDOUBLE_CLASS,
- mxSINGLE_CLASS,
- mxINT8_CLASS,
- mxUINT8_CLASS,
- mxINT16_CLASS,
- mxUINT16_CLASS,
- mxINT32_CLASS,
- mxUINT32_CLASS,
- )
-
-class mat_struct(object):
- ''' Placeholder for holding read data from structs '''
- pass
-
-class mat_obj(object):
- ''' Placeholder for holding read data from objects '''
- pass
-
-class Mat5ArrayReader(MatArrayReader):
- ''' Class to get Mat5 arrays
-
- Provides element reader functions, header reader, matrix reader
- factory function
- '''
-
- def __init__(self, mat_stream, dtypes, processor_func, codecs, class_dtypes):
- super(Mat5ArrayReader, self).__init__(mat_stream,
- dtypes,
- processor_func,
- )
- self.codecs = codecs
- self.class_dtypes = class_dtypes
-
- def read_element(self, copy=True):
- raw_tag = self.mat_stream.read(8)
- tag = N.ndarray(shape=(),
- dtype=self.dtypes['tag_full'],
- buffer = raw_tag)
- mdtype = tag['mdtype'].item()
- byte_count = mdtype >> 16
- if byte_count: # small data element format
- if byte_count > 4:
- raise ValueError, 'Too many bytes for sde format'
- mdtype = mdtype & 0xFFFF
- dt = self.dtypes[mdtype]
- el_count = byte_count / dt.itemsize
- return N.ndarray(shape=(el_count,),
- dtype=dt,
- buffer=raw_tag[4:])
- byte_count = tag['byte_count'].item()
- if mdtype == miMATRIX:
- return self.current_getter(byte_count).get_array()
- if mdtype in self.codecs: # encoded char data
- raw_str = self.mat_stream.read(byte_count)
- codec = self.codecs[mdtype]
- if not codec:
- raise TypeError, 'Do not support encoding %d' % mdtype
- el = raw_str.decode(codec)
- else: # numeric data
- dt = self.dtypes[mdtype]
- el_count = byte_count / dt.itemsize
- el = N.ndarray(shape=(el_count,),
- dtype=dt,
- buffer=self.mat_stream.read(byte_count))
- if copy:
- el = el.copy()
- mod8 = byte_count % 8
- if mod8:
- self.mat_stream.seek(8 - mod8, 1)
- return el
-
- def matrix_getter_factory(self):
- ''' Returns reader for next matrix at top level '''
- tag = self.read_dtype(self.dtypes['tag_full'])
- mdtype = tag['mdtype'].item()
- byte_count = tag['byte_count'].item()
- next_pos = self.mat_stream.tell() + byte_count
- if mdtype == miCOMPRESSED:
- getter = Mat5ZArrayReader(self, byte_count).matrix_getter_factory()
- elif not mdtype == miMATRIX:
- raise TypeError, \
- 'Expecting miMATRIX type here, got %d' % mdtype
- else:
- getter = self.current_getter(byte_count)
- getter.next_position = next_pos
- return getter
-
- def current_getter(self, byte_count):
- ''' Return matrix getter for current stream position
-
- Returns matrix getters at top level and sub levels
- '''
- if not byte_count: # an empty miMATRIX can contain no bytes
- return Mat5EmptyMatrixGetter(self)
- af = self.read_dtype(self.dtypes['array_flags'])
- header = {}
- flags_class = af['flags_class']
- mc = flags_class & 0xFF
- header['mclass'] = mc
- header['is_logical'] = flags_class >> 9 & 1
- header['is_global'] = flags_class >> 10 & 1
- header['is_complex'] = flags_class >> 11 & 1
- header['nzmax'] = af['nzmax']
- header['dims'] = self.read_element()
- header['name'] = self.read_element().tostring()
- if mc in mx_numbers:
- return Mat5NumericMatrixGetter(self, header)
- if mc == mxSPARSE_CLASS:
- return Mat5SparseMatrixGetter(self, header)
- if mc == mxCHAR_CLASS:
- return Mat5CharMatrixGetter(self, header)
- if mc == mxCELL_CLASS:
- return Mat5CellMatrixGetter(self, header)
- if mc == mxSTRUCT_CLASS:
- return Mat5StructMatrixGetter(self, header)
- if mc == mxOBJECT_CLASS:
- return Mat5ObjectMatrixGetter(self, header)
- raise TypeError, 'No reader for class code %s' % mc
-
-
-class Mat5ZArrayReader(Mat5ArrayReader):
- ''' Getter for compressed arrays
-
- Reads and uncompresses gzipped stream on init, providing wrapper
- for this new sub-stream.
- '''
- def __init__(self, array_reader, byte_count):
- '''Reads and uncompresses gzipped stream'''
- data = array_reader.mat_stream.read(byte_count)
- super(Mat5ZArrayReader, self).__init__(
- StringIO(zlib.decompress(data)),
- array_reader.dtypes,
- array_reader.processor_func,
- array_reader.codecs,
- array_reader.class_dtypes)
-
-
-class Mat5MatrixGetter(MatMatrixGetter):
- ''' Base class for getting Mat5 matrices
-
- Gets current read information from passed array_reader
- '''
-
- def __init__(self, array_reader, header):
- super(Mat5MatrixGetter, self).__init__(array_reader, header)
- self.class_dtypes = array_reader.class_dtypes
- self.codecs = array_reader.codecs
- self.is_global = header['is_global']
- self.mat_dtype = None
-
- def read_element(self, *args, **kwargs):
- return self.array_reader.read_element(*args, **kwargs)
-
-
-class Mat5EmptyMatrixGetter(Mat5MatrixGetter):
- ''' Dummy class to return empty array for empty matrix
- '''
- def __init__(self, array_reader):
- self.array_reader = array_reader
- self.mat_stream = array_reader.mat_stream
- self.data_position = self.mat_stream.tell()
- self.header = {}
- self.is_global = False
- self.mat_dtype = 'f8'
-
- def get_raw_array(self):
- return N.array([[]])
-
-
-class Mat5NumericMatrixGetter(Mat5MatrixGetter):
-
- def __init__(self, array_reader, header):
- super(Mat5NumericMatrixGetter, self).__init__(array_reader, header)
- if header['is_logical']:
- self.mat_dtype = N.dtype('bool')
- else:
- self.mat_dtype = self.class_dtypes[header['mclass']]
-
- def get_raw_array(self):
- if self.header['is_complex']:
- # avoid array copy to save memory
- res = self.read_element(copy=False)
- res_j = self.read_element(copy=False)
- res = res + (res_j * 1j)
- else:
- res = self.read_element()
- return N.ndarray(shape=self.header['dims'],
- dtype=res.dtype,
- buffer=res,
- order='F')
-
-
-class Mat5SparseMatrixGetter(Mat5MatrixGetter):
- def get_raw_array(self):
- rowind = self.read_element()
- indptr = self.read_element()
- if self.header['is_complex']:
- # avoid array copy to save memory
- data = self.read_element(copy=False)
- data_j = self.read_element(copy=False)
- data = data + (data_j * 1j)
- else:
- data = self.read_element()
- ''' From the matlab (TM) API documentation, last found here:
- http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_external/
- rowind are simply the row indices for all the (res) non-zero
- entries in the sparse array. rowind has nzmax entries, so
- may well have more entries than len(res), the actual number
- of non-zero entries, but rowind[len(res):] can be discarded
- and should be 0. indptr has length (number of columns + 1),
- and is such that, if D = diff(colind), D[j] gives the number
- of non-zero entries in column j. Because rowind values are
- stored in column order, this gives the column corresponding to
- each rowind
- '''
- if have_sparse:
- dims = self.header['dims']
- return scipy.sparse.csc_matrix((data,rowind,indptr), dims)
- else:
- return (dims, data, rowind, indptr)
-
-
-class Mat5CharMatrixGetter(Mat5MatrixGetter):
- def get_raw_array(self):
- res = self.read_element()
- # Convert non-string types to unicode
- if isinstance(res, N.ndarray):
- if res.dtype.type == N.uint16:
- codec = miUINT16_codec
- if self.codecs['uint16_len'] == 1:
- res = res.astype(N.uint8)
- elif res.dtype.type in (N.uint8, N.int8):
- codec = 'ascii'
- else:
- raise TypeError, 'Did not expect type %s' % res.dtype
- res = res.tostring().decode(codec)
- return N.ndarray(shape=self.header['dims'],
- dtype=N.dtype('U1'),
- buffer=N.array(res),
- order='F').copy()
-
-
-class Mat5CellMatrixGetter(Mat5MatrixGetter):
- def get_raw_array(self):
- # Account for fortran indexing of cells
- tupdims = tuple(self.header['dims'][::-1])
- length = N.product(tupdims)
- result = N.empty(length, dtype=object)
- for i in range(length):
- result[i] = self.get_item()
- return result.reshape(tupdims).T
-
- def get_item(self):
- return self.read_element()
-
-
-class Mat5StructMatrixGetter(Mat5CellMatrixGetter):
- def __init__(self, *args, **kwargs):
- super(Mat5StructMatrixGetter, self).__init__(*args, **kwargs)
- self.obj_template = mat_struct()
-
- def get_raw_array(self):
- namelength = self.read_element()[0]
- # get field names
- names = self.read_element()
- splitnames = [names[i:i+namelength] for i in \
- xrange(0,len(names),namelength)]
- self.obj_template._fieldnames = [x.tostring().strip('\x00')
- for x in splitnames]
- return super(Mat5StructMatrixGetter, self).get_raw_array()
-
- def get_item(self):
- item = pycopy(self.obj_template)
- for element in item._fieldnames:
- item.__dict__[element] = self.read_element()
- return item
-
-
-class Mat5ObjectMatrixGetter(Mat5StructMatrixGetter):
- def __init__(self, *args, **kwargs):
- super(Mat5StructMatrixGetter, self).__init__(*args, **kwargs)
- self.obj_template = mat_obj()
-
- def get_raw_array(self):
- self.obj_template._classname = self.read_element().tostring()
- return super(Mat5ObjectMatrixGetter, self).get_raw_array()
-
-
-class MatFile5Reader(MatFileReader):
- ''' Reader for Mat 5 mat files
-
- Adds the following attribute to base class
-
- uint16_codec - char codec to use for uint16 char arrays
- (defaults to system default codec)
- '''
-
- def __init__(self,
- mat_stream,
- byte_order=None,
- mat_dtype=False,
- squeeze_me=True,
- chars_as_strings=True,
- matlab_compatible=False,
- uint16_codec=None
- ):
- self.codecs = {}
- self._array_reader = Mat5ArrayReader(
- mat_stream,
- None,
- None,
- None,
- None,
- )
- super(MatFile5Reader, self).__init__(
- mat_stream,
- byte_order,
- mat_dtype,
- squeeze_me,
- chars_as_strings,
- matlab_compatible,
- )
- self._array_reader.processor_func = self.processor_func
- self.uint16_codec = uint16_codec
-
- def get_uint16_codec(self):
- return self._uint16_codec
- def set_uint16_codec(self, uint16_codec):
- if not uint16_codec:
- uint16_codec = sys.getdefaultencoding()
- # Set length of miUINT16 char encoding
- self.codecs['uint16_len'] = len(" ".encode(uint16_codec)) \
- - len(" ".encode(uint16_codec))
- self.codecs['uint16_codec'] = uint16_codec
- self._array_reader.codecs = self.codecs
- self._uint16_codec = uint16_codec
- uint16_codec = property(get_uint16_codec,
- set_uint16_codec,
- None,
- 'get/set uint16_codec')
-
- def set_dtypes(self):
- ''' Set dtypes and codecs '''
- self.dtypes = self.convert_dtypes(mdtypes_template)
- self.class_dtypes = self.convert_dtypes(mclass_dtypes_template)
- codecs = {}
- postfix = self.order_code == '<' and '_le' or '_be'
- for k, v in codecs_template.items():
- codec = v['codec']
- try:
- " ".encode(codec)
- except LookupError:
- codecs[k] = None
- continue
- if v['width'] > 1:
- codec += postfix
- codecs[k] = codec
- self.codecs.update(codecs)
- self.update_array_reader()
-
- def update_array_reader(self):
- self._array_reader.codecs = self.codecs
- self._array_reader.dtypes = self.dtypes
- self._array_reader.class_dtypes = self.class_dtypes
-
- def matrix_getter_factory(self):
- return self._array_reader.matrix_getter_factory()
-
- def guess_byte_order(self):
- self.mat_stream.seek(126)
- mi = self.mat_stream.read(2)
- self.mat_stream.seek(0)
- return mi == 'IM' and '<' or '>'
-
- def file_header(self):
- ''' Read in mat 5 file header '''
- hdict = {}
- hdr = self.read_dtype(self.dtypes['file_header'])
- hdict['__header__'] = hdr['description'].item().strip(' \t\n\000')
- v_major = hdr['version'] >> 8
- v_minor = hdr['version'] & 0xFF
- hdict['__version__'] = '%d.%d' % (v_major, v_minor)
- return hdict
-
- def format_looks_right(self):
- # Mat4 files have a zero somewhere in first 4 bytes
- self.mat_stream.seek(0)
- mopt_bytes = N.ndarray(shape=(4,),
- dtype=N.uint8,
- buffer = self.mat_stream.read(4))
- self.mat_stream.seek(0)
- return 0 not in mopt_bytes
-
-
-class Mat5MatrixWriter(MatStreamWriter):
-
- mat_tag = N.zeros((), mdtypes_template['tag_full'])
- mat_tag['mdtype'] = miMATRIX
-
- def __init__(self, file_stream, arr, name, is_global=False):
- super(Mat5MatrixWriter, self).__init__(file_stream, arr, name)
- self.is_global = is_global
-
- def write_dtype(self, arr):
- self.file_stream.write(arr.tostring())
-
- def write_element(self, arr, mdtype=None):
- # write tag, data
- tag = N.zeros((), mdtypes_template['tag_full'])
- if mdtype is None:
- tag['mdtype'] = np_to_mtypes[arr.dtype.str[1:]]
- else:
- tag['mdtype'] = mdtype
- tag['byte_count'] = arr.size*arr.itemsize
- self.write_dtype(tag)
- self.write_bytes(arr)
- # do 8 byte padding if needed
- if tag['byte_count']%8 != 0:
- pad = (1+tag['byte_count']//8)*8 - tag['byte_count']
- self.write_bytes(N.zeros((pad,),dtype='u1'))
-
- def write_header(self, mclass,
- is_global=False,
- is_complex=False,
- is_logical=False,
- nzmax=0):
- ''' Write header for given data options
- mclass - mat5 matrix class
- is_global - True if matrix is global
- is_complex - True is matrix is complex
- is_logical - True if matrix is logical
- nzmax - max non zero elements for sparse arrays
- '''
- self._mat_tag_pos = self.file_stream.tell()
- self.write_dtype(self.mat_tag)
- # write array flags (complex, global, logical, class, nzmax)
- af = N.zeros((), mdtypes_template['array_flags'])
- af['data_type'] = miUINT32
- af['byte_count'] = 8
- flags = is_complex << 3 | is_global << 2 | is_logical << 1
- af['flags_class'] = mclass | flags << 8
- af['nzmax'] = nzmax
- self.write_dtype(af)
- # write array shape
- self.arr=N.atleast_2d(self.arr)
- self.write_element(N.array(self.arr.shape, dtype='i4'))
- # write name
- self.write_element(N.ndarray(shape=len(self.name), dtype='S1', buffer=self.name))
-
- def update_matrix_tag(self):
- curr_pos = self.file_stream.tell()
- self.file_stream.seek(self._mat_tag_pos)
- self.mat_tag['byte_count'] = curr_pos - self._mat_tag_pos - 8
- self.write_dtype(self.mat_tag)
- self.file_stream.seek(curr_pos)
-
- def write(self):
- assert False, 'Not implemented'
-
-
-class Mat5NumericWriter(Mat5MatrixWriter):
-
- def write(self):
- imagf = self.arr.dtype.kind == 'c'
- try:
- mclass = np_to_mxtypes[self.arr.dtype.str[1:]]
- except KeyError:
- if imagf:
- self.arr = self.arr.astype('c128')
- else:
- self.arr = self.arr.astype('f8')
- mclass = mxDOUBLE_CLASS
- self.write_header(mclass=mclass,is_complex=imagf)
- if imagf:
- self.write_element(self.arr.real)
- self.write_element(self.arr.imag)
- else:
- self.write_element(self.arr)
- self.update_matrix_tag()
-
-class Mat5CharWriter(Mat5MatrixWriter):
- codec='ascii'
- def write(self):
- self.arr_to_chars()
- self.write_header(mclass=mxCHAR_CLASS)
- if self.arr.dtype.kind == 'U':
- # Recode unicode using self.codec
- n_chars = N.product(self.arr.shape)
- st_arr = N.ndarray(shape=(),
- dtype=self.arr_dtype_number(n_chars),
- buffer=self.arr)
- st = st_arr.item().encode(self.codec)
- self.arr = N.ndarray(shape=(len(st)), dtype='u1', buffer=st)
- self.write_element(self.arr,mdtype=miUTF8)
- self.update_matrix_tag()
-
-class Mat5UniCharWriter(Mat5CharWriter):
- codec='UTF8'
-
-
-class Mat5SparseWriter(Mat5MatrixWriter):
-
- def write(self):
- ''' Sparse matrices are 2D
- See docstring for Mat5SparseGetter
- '''
- imagf = self.arr.dtype.kind == 'c'
- N = self.arr.nnz
- ijd = N.zeros((N+1, 3+imagf), dtype='f8')
- for i in range(N):
- ijd[i,0], ijd[i,1] = self.arr.rowcol(i)
- ijd[:-1,0:2] += 1 # 1 based indexing
- if imagf:
- ijd[:-1,2] = self.arr.data.real
- ijd[:-1,3] = self.arr.data.imag
- else:
- ijd[:-1,2] = self.arr.data
- ijd[-1,0:2] = self.arr.shape
- self.write_header(P=miDOUBLE,
- T=mxSPARSE_CLASS,
- dims=ijd.shape)
- self.write_bytes(ijd)
-
-
-class Mat5WriterGetter(object):
- ''' Wraps stream and options, provides methods for getting Writer objects '''
- def __init__(self, stream, unicode_strings):
- self.stream = stream
- self.unicode_strings = unicode_strings
-
- def rewind(self):
- self.stream.seek(0)
-
- def matrix_writer_factory(self, arr, name, is_global=False):
- ''' Factory function to return matrix writer given variable to write
- stream - file or file-like stream to write to
- arr - array to write
- name - name in matlab (TM) workspace
- '''
- if have_sparse:
- if scipy.sparse.issparse(arr):
- return Mat5SparseWriter(self.stream, arr, name, is_global)
- arr = N.array(arr)
- if arr.dtype.hasobject:
- types, arr_type = self.classify_mobjects(arr)
- if arr_type == 'c':
- return Mat5CellWriter(self.stream, arr, name, is_global, types)
- elif arr_type == 's':
- return Mat5StructWriter(self.stream, arr, name, is_global)
- elif arr_type == 'o':
- return Mat5ObjectWriter(self.stream, arr, name, is_global)
- if arr.dtype.kind in ('U', 'S'):
- if self.unicode_strings:
- return Mat5UniCharWriter(self.stream, arr, name, is_global)
- else:
- return Mat5CharWriter(self.stream, arr, name, is_global)
- else:
- return Mat5NumericWriter(self.stream, arr, name, is_global)
-
- def classify_mobjects(self, objarr):
- ''' Function to classify objects passed for writing
- returns
- types - S1 array of same shape as objarr with codes for each object
- i - invalid object
- a - ndarray
- s - matlab struct
- o - matlab object
- arr_type - one of
- c - cell array
- s - struct array
- o - object array
- '''
- n = objarr.size
- types = N.empty((n,), dtype='S1')
- types[:] = 'i'
- type_set = set()
- flato = objarr.flat
- for i in range(n):
- obj = flato[i]
- if isinstance(obj, N.ndarray):
- types[i] = 'a'
- continue
- try:
- fns = tuple(obj._fieldnames)
- except AttributeError:
- continue
- try:
- cn = obj._classname
- except AttributeError:
- types[i] = 's'
- type_set.add(fns)
- continue
- types[i] = 'o'
- type_set.add((cn, fns))
- arr_type = 'c'
- if len(set(types))==1 and len(type_set) == 1:
- arr_type = types[0]
- return types.reshape(objarr.shape), arr_type
-
-
-class MatFile5Writer(MatFileWriter):
- ''' Class for writing mat5 files '''
- def __init__(self, file_stream,
- do_compression=False,
- unicode_strings=False,
- global_vars=None):
- super(MatFile5Writer, self).__init__(file_stream)
- self.do_compression = do_compression
- if global_vars:
- self.global_vars = global_vars
- else:
- self.global_vars = []
- self.writer_getter = Mat5WriterGetter(
- StringIO(),
- unicode_strings)
- # write header
- import os, time
- hdr = N.zeros((), mdtypes_template['file_header'])
- hdr['description']='MATLAB 5.0 MAT-file Platform: %s, Created on: %s' % (
- os.name,time.asctime())
- hdr['version']= 0x0100
- hdr['endian_test']=N.ndarray(shape=(),dtype='S2',buffer=N.uint16(0x4d49))
- file_stream.write(hdr.tostring())
-
- def get_unicode_strings(self):
- return self.write_getter.unicode_strings
- def set_unicode_strings(self, unicode_strings):
- self.writer_getter.unicode_strings = unicode_strings
- unicode_strings = property(get_unicode_strings,
- set_unicode_strings,
- None,
- 'get/set unicode strings property')
-
- def put_variables(self, mdict):
- for name, var in mdict.items():
- is_global = name in self.global_vars
- self.writer_getter.rewind()
- self.writer_getter.matrix_writer_factory(
- var,
- name,
- is_global,
- ).write()
- stream = self.writer_getter.stream
- if self.do_compression:
- str = zlib.compress(stream.getvalue(stream.tell()))
- tag = N.empty((), mdtypes_template['tag_full'])
- tag['mdtype'] = miCOMPRESSED
- tag['byte_count'] = len(str)
- self.file_stream.write(tag.tostring() + str)
- else:
- self.file_stream.write(stream.getvalue(stream.tell()))
Deleted: branches/io_new/miobase.py
===================================================================
--- branches/io_new/miobase.py 2007-12-14 23:31:02 UTC (rev 3658)
+++ branches/io_new/miobase.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -1,379 +0,0 @@
-# Authors: Travis Oliphant, Matthew Brett
-
-"""
-Base classes for matlab (TM) file stream reading
-"""
-
-import sys
-
-import numpy as N
-
-try:
- import scipy.sparse
- have_sparse = 1
-except ImportError:
- have_sparse = 0
-
-
-def small_product(arr):
- ''' Faster than product for small arrays '''
- res = 1
- for e in arr:
- res *= e
- return res
-
-class ByteOrder(object):
- ''' Namespace for byte ordering '''
- little_endian = sys.byteorder == 'little'
- native_code = little_endian and '<' or '>'
- swapped_code = little_endian and '>' or '<'
-
- def to_numpy_code(code):
- if code is None:
- return ByteOrder.native_code
- if code in ('little', '<', 'l', 'L'):
- return '<'
- elif code in ('BIG', '>', 'B', 'b'):
- return '>'
- elif code in ('native', '='):
- return ByteOrder.native_code
- elif code in ('swapped'):
- return ByteOrder.swapped_code
- else:
- raise ValueError, 'We cannot handle byte order %s' % byte_order
- to_numpy_code = staticmethod(to_numpy_code)
-
-
-class MatStreamAgent(object):
- ''' Base object for readers / getters from mat file streams
-
- Attaches to initialized stream
-
- Base class for "getters" - which do store state of what they are
- reading on itialization, and therefore need to be initialized
- before each read, and "readers" which do not store state, and only
- need to be initialized once on object creation
-
- Implements common array reading functions
-
- Inputs mat_steam - MatFileReader object
- '''
-
- def __init__(self, mat_stream):
- self.mat_stream = mat_stream
-
- def read_dtype(self, a_dtype):
- ''' Generic get of byte stream data of known type
-
- Inputs
- a_dtype - dtype of array
-
- a_dtype is assumed to be correct endianness
- '''
- num_bytes = a_dtype.itemsize
- arr = N.ndarray(shape=(),
- dtype=a_dtype,
- buffer=self.mat_stream.read(num_bytes),
- order='F')
- return arr
-
- def read_ztstring(self, num_bytes):
- return self.mat_stream.read(num_bytes).strip('\x00')
-
-
-class MatFileReader(MatStreamAgent):
- """ Base object for reading mat files
-
- mat_stream - initialized byte stream object - file io interface object
- byte_order - byte order ('native', 'little', 'BIG')
- in ('native', '=')
- or in ('little', '<')
- or in ('BIG', '>')
- mat_dtype - return arrays in same dtype as loaded into matlab
- (instead of the dtype with which they are saved)
- squeeze_me - whether to squeeze unit dimensions or not
- chars_as_strings - whether to convert char arrays to string arrays
- mat_dtype - return matrices with datatype that matlab would load as
- (rather than in the datatype matlab saves as)
- matlab_compatible - returns matrices as would be loaded by matlab
- (implies squeeze_me=False, chars_as_strings=False
- mat_dtype=True)
-
- To make this class functional, you will need to override the
- following methods:
-
- set_dtypes - sets data types defs from byte order
- matrix_getter_factory - gives object to fetch next matrix from stream
- format_looks_right - returns True if format looks correct for
- this file type (Mat4, Mat5)
- guess_byte_order - guesses file byte order from file
- """
-
- def __init__(self, mat_stream,
- byte_order=None,
- mat_dtype=False,
- squeeze_me=True,
- chars_as_strings=True,
- matlab_compatible=False,
- ):
- # Initialize stream
- self.mat_stream = mat_stream
- self.dtypes = {}
- if not byte_order:
- byte_order = self.guess_byte_order()
- self.order_code = byte_order # sets dtypes and other things too
- if matlab_compatible:
- self.set_matlab_compatible()
- else:
- self._squeeze_me = squeeze_me
- self._chars_as_strings = chars_as_strings
- self._mat_dtype = mat_dtype
- self.processor_func = self.get_processor_func()
-
- def set_matlab_compatible(self):
- ''' Sets options to return arrays as matlab (tm) loads them '''
- self._mat_dtype = True
- self._squeeze_me = False
- self._chars_as_strings = False
- self.processor_func = self.get_processor_func()
-
- def get_mat_dtype(self):
- return self._mat_dtype
- def set_mat_dtype(self, mat_dtype):
- self._mat_dtype = mat_dtype
- self.processor_func = self.get_processor_func()
- mat_dtype = property(get_mat_dtype,
- set_mat_dtype,
- None,
- 'get/set mat_dtype property')
-
- def get_squeeze_me(self):
- return self._squeeze_me
- def set_squeeze_me(self, squeeze_me):
- self._squeeze_me = squeeze_me
- self.processor_func = self.get_processor_func()
- squeeze_me = property(get_squeeze_me,
- set_squeeze_me,
- None,
- 'get/set squeeze me property')
-
- def get_chars_as_strings(self):
- return self._chars_as_strings
- def set_chars_as_strings(self, chars_as_strings):
- self._chars_as_strings = chars_as_strings
- self.processor_func = self.get_processor_func()
- chars_as_strings = property(get_chars_as_strings,
- set_chars_as_strings,
- None,
- 'get/set squeeze me property')
-
- def get_order_code(self):
- return self._order_code
- def set_order_code(self, order_code):
- order_code = ByteOrder.to_numpy_code(order_code)
- self._order_code = order_code
- self.set_dtypes()
- order_code = property(get_order_code,
- set_order_code,
- None,
- 'get/set order code')
-
- def set_dtypes(self):
- assert False, 'Not implemented'
-
- def convert_dtypes(self, dtype_template):
- dtypes = dtype_template.copy()
- for k in dtypes:
- dtypes[k] = N.dtype(dtypes[k]).newbyteorder(
- self.order_code)
- return dtypes
-
- def matrix_getter_factory(self):
- assert False, 'Not implemented'
-
- def format_looks_right(self):
- "Return True if the format looks right for this object"
- assert False, 'Not implemented'
-
- def file_header(self):
- return {}
-
- def guess_byte_order(self):
- assert 0, 'Not implemented'
-
- def get_processor_func(self):
- ''' Processing to apply to read matrices
-
- Function applies options to matrices. We have to pass this
- function into the reader routines because Mat5 matrices
- occur as submatrices - in cell arrays, structs and objects -
- so we will not see these in the main variable getting routine
- here.
-
- The read array is the first argument.
- The getter, passed as second argument to the function, must
- define properties, iff mat_dtype option is True:
-
- mat_dtype - data type when loaded into matlab (tm)
- (None for no conversion)
-
- func returns the processed array
- '''
-
- def func(arr, getter):
- if arr.dtype.kind == 'U' and self.chars_as_strings:
- # Convert char array to string or array of strings
- dims = arr.shape
- if len(dims) >= 2: # return array of strings
- dtt = self.order_code + 'U'
- n_dims = dims[:-1]
- str_arr = arr.reshape(
- (small_product(n_dims),
- dims[-1]))
- arr = N.empty(n_dims, dtype=object)
- for i in range(0, n_dims[-1]):
- arr[...,i] = self.chars_to_str(str_arr[i])
- else: # return string
- arr = self.chars_to_str(arr)
- if self.mat_dtype:
- # Apply options to replicate matlab's (TM)
- # load into workspace
- if getter.mat_dtype is not None:
- arr = arr.astype(getter.mat_dtype)
- if self.squeeze_me:
- arr = N.squeeze(arr)
- if not arr.size:
- arr = N.array([])
- elif not arr.shape: # 0d coverted to scalar
- arr = arr.item()
- return arr
- return func
-
- def chars_to_str(self, str_arr):
- ''' Convert string array to string '''
- dt = N.dtype('U' + str(small_product(str_arr.shape)))
- return N.ndarray(shape=(),
- dtype = dt,
- buffer = str_arr.copy()).item()
-
- def get_variables(self, variable_names=None):
- ''' get variables from stream as dictionary
-
- variable_names - optional list of variable names to get
-
- If variable_names is None, then get all variables in file
- '''
- if isinstance(variable_names, basestring):
- variable_names = [variable_names]
- self.mat_stream.seek(0)
- mdict = self.file_header()
- mdict['__globals__'] = []
- while not self.end_of_stream():
- getter = self.matrix_getter_factory()
- name = getter.name
- if variable_names and name not in variable_names:
- getter.to_next()
- continue
- res = getter.get_array()
- mdict[name] = res
- if getter.is_global:
- mdict['__globals__'].append(name)
- if variable_names:
- variable_names.remove(name)
- if not variable_names:
- break
- return mdict
-
- def end_of_stream(self):
- b = self.mat_stream.read(1)
- self.mat_stream.seek(-1,1)
- return len(b) == 0
-
-
-class MatMatrixGetter(MatStreamAgent):
- """ Base class for matrix getters
-
- Getters are stateful versions of agents, and record state of
- current read on initialization, so need to be created for each
- read - one-shot objects.
-
- MatrixGetters are initialized with the content of the matrix
- header
-
- Accepts
- array_reader - array reading object (see below)
- header - header dictionary for matrix being read
- """
-
- def __init__(self, array_reader, header):
- super(MatMatrixGetter, self).__init__(array_reader.mat_stream)
- self.array_reader = array_reader
- self.dtypes = array_reader.dtypes
- self.header = header
- self.name = header['name']
-
- def get_array(self):
- ''' Gets an array from matrix, and applies any necessary processing '''
- arr = self.get_raw_array()
- return self.array_reader.processor_func(arr, self)
-
- def get_raw_array(self):
- assert False, 'Not implemented'
-
- def to_next(self):
- self.mat_stream.seek(self.next_position)
-
-
-class MatArrayReader(MatStreamAgent):
- ''' Base class for array readers
-
- The array_reader contains information about the current reading
- process, such as byte ordered dtypes and the processing function
- to apply to matrices as they are read, as well as routines for
- reading matrix compenents.
- '''
-
- def __init__(self, mat_stream, dtypes, processor_func):
- self.mat_stream = mat_stream
- self.dtypes = dtypes
- self.processor_func = processor_func
-
- def matrix_getter_factory(self):
- assert False, 'Not implemented'
-
-
-class MatStreamWriter(object):
- ''' Base object for writing to mat files '''
- def __init__(self, file_stream, arr, name):
- self.file_stream = file_stream
- self.arr = arr
- dt = self.arr.dtype
- if not dt.isnative:
- self.arr = self.arr.astype(dt.newbyteorder('='))
- self.name = name
-
- def arr_dtype_number(self, num):
- ''' Return dtype for given number of items per element'''
- return N.dtype(self.arr.dtype.str[:2] + str(num))
-
- def arr_to_chars(self):
- ''' Convert string array to char array '''
- dims = list(self.arr.shape)
- if not dims:
- dims = [1]
- dims.append(int(self.arr.dtype.str[2:]))
- self.arr = N.ndarray(shape=dims,
- dtype=self.arr_dtype_number(1),
- buffer=self.arr)
-
- def write_bytes(self, arr):
- self.file_stream.write(arr.tostring(order='F'))
-
- def write_string(self, s):
- self.file_stream.write(s)
-
-
-class MatFileWriter(object):
- ''' Base class for Mat file writers '''
- def __init__(self, file_stream):
- self.file_stream = file_stream
Modified: branches/io_new/tests/test_mio.py
===================================================================
--- branches/io_new/tests/test_mio.py 2007-12-14 23:31:02 UTC (rev 3658)
+++ branches/io_new/tests/test_mio.py 2007-12-14 23:33:47 UTC (rev 3659)
@@ -11,8 +11,8 @@
import scipy.sparse as SP
set_package_path()
-from scipy.io.mio import loadmat, savemat
-from scipy.io.mio5 import mat_obj, mat_struct
+from scipy.io.matlab.mio import loadmat, savemat
+from scipy.io.matlab.mio5 import mat_obj, mat_struct
restore_path()
try: # Python 2.3 support
More information about the Scipy-svn
mailing list