[Scipy-svn] r2203 - in trunk/Lib/io: . tests
scipy-svn at scipy.org
scipy-svn at scipy.org
Tue Sep 19 18:14:48 EDT 2006
Author: matthew.brett at gmail.com
Date: 2006-09-19 17:14:27 -0500 (Tue, 19 Sep 2006)
New Revision: 2203
Modified:
trunk/Lib/io/mio.py
trunk/Lib/io/mio4.py
trunk/Lib/io/mio5.py
trunk/Lib/io/miobase.py
trunk/Lib/io/tests/test_mio.py
Log:
Added mat4 sparse save; separated mat4 and mat5 tests; docstring edits
Modified: trunk/Lib/io/mio.py
===================================================================
--- trunk/Lib/io/mio.py 2006-09-19 15:16:02 UTC (rev 2202)
+++ trunk/Lib/io/mio.py 2006-09-19 22:14:27 UTC (rev 2203)
@@ -1,7 +1,7 @@
# Authors: Travis Oliphant, Matthew Brett
"""
-Module for reading and writing matlab .mat files
+Module for reading and writing matlab (TM) .mat files
"""
import os
@@ -15,7 +15,7 @@
def mat_reader_factory(file_name, append_mat=True):
- """Create reader for matlab format files
+ """Create reader for matlab (TM) .mat format files
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
@@ -25,7 +25,8 @@
Inputs:
- file_name -- name of the mat file (don't need .mat extension if append_mat=True)
+ file_name -- name of the mat file (don't need .mat extension
+ if append_mat=True)
append_mat -- True to append the .mat extension to the end of the
given filename.
"""
@@ -74,8 +75,9 @@
def savemat(file_name, mdict, appendmat=True):
"""Save a dictionary of names and arrays into the MATLAB-style .mat file.
- This saves the arrayobjects in the given dictionary to a matlab Version 4
- style .mat file.
+ This saves the arrayobjects in the given dictionary to a matlab
+ Version 4 style .mat file.
+
@appendmat - if true, appends '.mat' extension to filename, if not present
"""
if appendmat and file_name[-4:] != ".mat":
Modified: trunk/Lib/io/mio4.py
===================================================================
--- trunk/Lib/io/mio4.py 2006-09-19 15:16:02 UTC (rev 2202)
+++ trunk/Lib/io/mio4.py 2006-09-19 22:14:27 UTC (rev 2203)
@@ -1,4 +1,4 @@
-''' Classes for read / write of matlab 4 files
+''' Classes for read / write of matlab (TM) 4 files
'''
from numpy import *
@@ -60,11 +60,11 @@
name
dims - shape of matrix as stored (see sparse reader)
dtype - numpy dtype of matrix
- mclass - matlab code for class of matrix
+ mclass - matlab (TM) code for class of matrix
is_char - True if these are char data
is_numeric - True if these are numeric data
is_complex - True if data are complex
- original_dtype - data type in matlab workspace
+ original_dtype - data type in matlab (TM) workspace
'''
def __init__(self):
self.next_position = None
@@ -159,26 +159,26 @@
class Mat4SparseGetter(Mat4MatrixGetter):
''' Read sparse matrix type
- Matlab 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 of the data; 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
+ 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):
self.header.original_dtype = dtype(float64)
res = self.read_hdr_array()
tmp = res[:-1,:]
dims = res[-1,0:2]
- ij = transpose(tmp[:,0:2]) - 1 # for matlab 1-based indexing
+ ij = transpose(tmp[:,0:2]) - 1 # for 1-based indexing
vals = tmp[:,2]
if res.shape[1] == 4:
self.header.is_complex = True
@@ -207,7 +207,7 @@
return self._array_reader.matrix_getter_factory()
def format_looks_right(self):
- # Matlab 4 files have a zero somewhere in first 4 bytes
+ # Mat4 files have a zero somewhere in first 4 bytes
self.mat_stream.seek(0)
mopt_bytes = self.read_bytes(4)
self.mat_stream.seek(0)
@@ -224,8 +224,15 @@
class Mat4MatrixWriter(MatStreamWriter):
- def write_header(self, P, T, dims, imagf):
- ''' Write header for data type, matrix class, dims, complex flag '''
+ 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 = empty((), mdtypes_template['header'])
M = not ByteOrder.little_endian
O = 0
@@ -264,7 +271,9 @@
else:
self.arr = self.arr.astype('f8')
P = miDOUBLE
- self.write_header(P, 0, self.arr.shape, imagf)
+ self.write_header(P=P,
+ T=mxFULL_CLASS,
+ imagf=imagf)
if imagf:
self.write_bytes(self.arr.real)
self.write_bytes(self.arr.imag)
@@ -278,7 +287,8 @@
self.arr_to_chars()
self.arr_to_2d()
dims = self.arr.shape
- self.write_header(miUINT8, 1, dims, 0)
+ self.write_header(P=miUINT8,
+ T=mxCHAR_CLASS)
if self.arr.dtype.kind == 'U':
# Recode unicode to ascii
n_chars = product(dims)
@@ -290,18 +300,45 @@
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'
+ N = self.arr.nnz
+ ijd = 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)
+
+
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 workspace
+ @name - name in matlab (TM) workspace
'''
+ if have_sparse:
+ if scipy.sparse.issparse(arr):
+ return Mat4SparseWriter(stream, arr, name)
arr = array(arr)
if arr.dtype.hasobject:
raise TypeError, 'Cannot save object arrays in Mat4'
if have_sparse:
if scipy.sparse.issparse(arr):
- raise TypeError, 'Cannot save sparse arrays yet'
+ return Mat4SparseWriter(stream, arr, name)
if arr.dtype.kind in ('U', 'S'):
return Mat4CharWriter(stream, arr, name)
else:
Modified: trunk/Lib/io/mio5.py
===================================================================
--- trunk/Lib/io/mio5.py 2006-09-19 15:16:02 UTC (rev 2202)
+++ trunk/Lib/io/mio5.py 2006-09-19 22:14:27 UTC (rev 2203)
@@ -1,4 +1,4 @@
-''' Classes for read / write of matlab 5 files
+''' Classes for read / write of matlab (TM) 5 files
'''
# Small fragments of current code adapted from matfile.py by Heiko
@@ -102,10 +102,10 @@
mxDOUBLE_CLASS: 'f8',
}
-''' Before release v7.1 (release 14) matlab used the system default
-character encoding scheme padded out to 16-bits. Release 14 and later
-use Unicode. When saving character data, matlab R14 checks if it can
-be encoded in 7-bit ascii, and saves in that format if so.'''
+''' 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},
@@ -145,13 +145,13 @@
next_position - start position of next matrix
name
dtype - numpy dtype of matrix
- mclass - matlab code for class of matrix
+ mclass - matlab (TM) code for class of matrix
dims - shape of matrix as stored (see sparse reader)
is_complex - True if data are complex
is_char - True if these are char data
- is_global - is a global variable in matlab workspace
+ is_global - is a global variable in matlab (TM) workspace
is_numeric - is basic numeric matrix
- original_dtype - data type when saved from matlab
+ original_dtype - data type when saved from matlab (TM)
'''
def __init__(self):
self.next_position = None
@@ -219,7 +219,8 @@
try:
dt = self.dtypes[tag.mdtype]
except KeyError:
- raise TypeError, 'Do not know matlab data code %d' % tag.mdtype
+ raise TypeError, 'Do not know matlab (TM) data code %d' \
+ % tag.mdtype
el_count = tag.byte_count / dt.itemsize
el = self.read_array(dt, a_shape=(el_count), copy=copy)
if tag.skip:
@@ -369,7 +370,7 @@
res = res + (res_j * 1j)
else:
res = self.read_element()
- ''' From the matlab API documentation, last found here:
+ ''' 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
@@ -555,7 +556,7 @@
return hdict
def format_looks_right(self):
- # Matlab 4 files have a zero somewhere in first 4 bytes
+ # Mat4 files have a zero somewhere in first 4 bytes
self.mat_stream.seek(0)
mopt_bytes = self.read_bytes(4)
self.mat_stream.seek(0)
Modified: trunk/Lib/io/miobase.py
===================================================================
--- trunk/Lib/io/miobase.py 2006-09-19 15:16:02 UTC (rev 2202)
+++ trunk/Lib/io/miobase.py 2006-09-19 22:14:27 UTC (rev 2203)
@@ -1,7 +1,7 @@
# Authors: Travis Oliphant, Matthew Brett
"""
-Base classes for matlab file stream reading
+Base classes for matlab (TM) file stream reading
"""
import sys
@@ -100,7 +100,7 @@
or in ('little', '<')
or in ('BIG', '>')
@base_name - base name for unnamed variables
- @matlab_compatible - return arrays as matlab saved them
+ @matlab_compatible - return arrays as matlab (TM) saved them
@squeeze_me - whether to squeeze unit dimensions or not
@chars_as_strings - whether to convert char arrays to string arrays
@@ -184,7 +184,7 @@
''' Processing to apply to read matrices
Function applies options to matrices. We have to pass this
- function into the reader routines because Matlab 5 matrices
+ 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.
@@ -206,11 +206,12 @@
else: # return string
arr = self.chars_to_str(arr)
if self.matlab_compatible:
- # Apply options to replicate matlab's load into workspace
+ # Apply options to replicate matlab's (TM)
+ # load into workspace
if header.is_logical:
arr = arr.astype(bool)
elif header.is_numeric:
- # Cast as original matlab type
+ # Cast as original matlab (TM) type
if header.original_dtype:
arr = arr.astype(header.original_dtype)
if self.squeeze_me:
@@ -331,7 +332,7 @@
return dtype(self.arr.dtype.str[:2] + str(num))
def arr_to_chars(self):
- ''' Converts string array to matlab char array '''
+ ''' Convert string array to char array '''
dims = list(self.arr.shape)
if not dims:
dims = [1]
Modified: trunk/Lib/io/tests/test_mio.py
===================================================================
--- trunk/Lib/io/tests/test_mio.py 2006-09-19 15:16:02 UTC (rev 2202)
+++ trunk/Lib/io/tests/test_mio.py 2006-09-19 22:14:27 UTC (rev 2203)
@@ -100,79 +100,80 @@
# Define cases to test
theta = pi/4*arange(9,dtype=float)
- case_table = [
+ case_table4 = [
{'name': 'double',
'expected': {'testdouble': theta}
}]
- case_table.append(
+ case_table4.append(
{'name': 'string',
'expected': {'teststring': u'"Do nine men interpret?" "Nine men," I nod.'},
})
- case_table.append(
+ case_table4.append(
{'name': 'complex',
'expected': {'testcomplex': cos(theta) + 1j*sin(theta)}
})
- case_table.append(
- {'name': 'cell',
- 'expected': {'testcell':
- array([u'This cell contains this string and 3 arrays of '+\
- 'increasing length',
- array(1), array([1,2]), array([1,2,3])],
- dtype=object)}
- })
- st = mat_struct()
- st.stringfield = u'Rats live on no evil star.'
- st.doublefield = array([sqrt(2),exp(1),pi])
- st.complexfield = (1+1j)*array([sqrt(2),exp(1),pi])
- case_table.append(
- {'name': 'struct',
- 'expected': {'teststruct': st}
- })
A = zeros((3,5))
A[0] = range(1,6)
A[:,0] = range(1,4)
- case_table.append(
+ case_table4.append(
{'name': 'matrix',
'expected': {'testmatrix': A},
})
- case_table.append(
- {'name': '3dmatrix',
- 'expected': {'test3dmatrix': transpose(reshape(range(1,25), (4,3,2)))}
- })
- case_table.append(
+ case_table4.append(
{'name': 'sparse',
'expected': {'testsparse': SP.csc_matrix(A)},
})
B = A.astype(complex)
B[0,0] += 1j
- case_table.append(
+ case_table4.append(
{'name': 'sparsecomplex',
'expected': {'testsparsecomplex': SP.csc_matrix(B)},
})
- case_table.append(
+ case_table4.append(
{'name': 'multi',
'expected': {'theta': theta,
'a': A},
})
- case_table.append(
+ case_table4.append(
{'name': 'minus',
'expected': {'testminus': array(-1)},
})
- case_table.append(
+ case_table4.append(
{'name': 'onechar',
'expected': {'testonechar': u'r'},
})
- case_table.append(
+ case_table5 = [
+ {'name': 'cell',
+ 'expected': {'testcell':
+ array([u'This cell contains this string and 3 arrays of '+\
+ 'increasing length',
+ array(1), array([1,2]), array([1,2,3])],
+ dtype=object)}
+ }]
+ case_table5.append(
{'name': 'stringarray',
- 'expected': {'teststringarray': array([u'one ', u'two ', u'three'], dtype=object)},
+ 'expected': {'teststringarray': array(
+ [u'one ', u'two ', u'three'], dtype=object)},
})
+ case_table5.append(
+ {'name': '3dmatrix',
+ 'expected': {'test3dmatrix': transpose(reshape(range(1,25), (4,3,2)))}
+ })
+ st = mat_struct()
+ st.stringfield = u'Rats live on no evil star.'
+ st.doublefield = array([sqrt(2),exp(1),pi])
+ st.complexfield = (1+1j)*array([sqrt(2),exp(1),pi])
+ case_table5.append(
+ {'name': 'struct',
+ 'expected': {'teststruct': st}
+ })
a = array([array(1),
array([array(2), array(3),
array([array(4), array(5)],
dtype=object)],
dtype=object)],
dtype=object)
- case_table.append(
+ case_table5.append(
{'name': 'cellnest',
'expected': {'testcellnest': a},
})
@@ -180,7 +181,7 @@
st.one = array(1)
st.two = mat_struct()
st.two.three = u'number 3'
- case_table.append(
+ case_table5.append(
{'name': 'structnest',
'expected': {'teststructnest': st}
})
@@ -189,7 +190,7 @@
a[0].two = array(2)
a[1].one = u'number 1'
a[1].two = u'number 2'
- case_table.append(
+ case_table5.append(
{'name': 'structarr',
'expected': {'teststructarr': a}
})
@@ -201,19 +202,19 @@
a.isEmpty = array(0)
a.numArgs = array(1)
a.version = array(1)
- case_table.append(
+ case_table5.append(
{'name': 'object',
'expected': {'testobject': a}
})
u_str = file(
os.path.join(test_data_path, 'japanese_utf8.txt'),
'rb').read().decode('utf-8')
- case_table.append(
+ case_table5.append(
{'name': 'unicode',
'expected': {'testunicode': u_str}
})
# add load tests
- for case in case_table:
+ for case in case_table4 + case_table5:
name = case['name']
expected = case['expected']
filt = os.path.join(test_data_path, 'test%s_*.mat' % name)
@@ -221,24 +222,7 @@
assert files, "No files for test %s using filter %s" % (name, filt)
exec 'check_%s = _make_check_case(name, files, expected)' % name
# round trip tests
- case_table = [
- {'name': 'double',
- 'expected': {'testdouble': theta}
- }]
- case_table.append(
- {'name': 'string',
- 'expected': {'teststring': u'"Do nine men interpret?" "Nine men," I nod.'},
- })
- case_table.append(
- {'name': 'complex',
- 'expected': {'testcomplex': cos(theta) + 1j*sin(theta)}
- })
- case_table.append(
- {'name': 'multi',
- 'expected': {'theta': theta,
- 'a': A},
- })
- for case in case_table:
+ for case in case_table4:
name = case['name'] + '_round_trip'
expected = case['expected']
exec 'check_%s = _make_rt_check_case(name, expected)' % name
More information about the Scipy-svn
mailing list