[Scipy-svn] r5563 - in trunk/scipy/io/matlab: . tests
scipy-svn at scipy.org
scipy-svn at scipy.org
Wed Feb 18 23:30:32 EST 2009
Author: matthew.brett at gmail.com
Date: 2009-02-18 22:30:03 -0600 (Wed, 18 Feb 2009)
New Revision: 5563
Modified:
trunk/scipy/io/matlab/mio5.py
trunk/scipy/io/matlab/miobase.py
trunk/scipy/io/matlab/tests/test_mio.py
Log:
More specific shapes for 1d arrays, with tests
Modified: trunk/scipy/io/matlab/mio5.py
===================================================================
--- trunk/scipy/io/matlab/mio5.py 2009-02-19 02:58:23 UTC (rev 5562)
+++ trunk/scipy/io/matlab/mio5.py 2009-02-19 04:30:03 UTC (rev 5563)
@@ -22,7 +22,7 @@
import scipy.sparse
from miobase import MatFileReader, MatArrayReader, MatMatrixGetter, \
- MatFileWriter, MatStreamWriter, filldoc
+ MatFileWriter, MatStreamWriter, filldoc, matdims
miINT8 = 1
miUINT8 = 2
@@ -706,9 +706,7 @@
if mclass is None:
mclass = self.default_mclass
if shape is None:
- shape = self.arr.shape
- if len(shape) < 2:
- shape = shape + (0,) * (len(shape)-2)
+ shape = matdims(self.arr)
self._mat_tag_pos = self.file_stream.tell()
self.write_dtype(self.mat_tag)
# write array flags (complex, global, logical, class, nzmax)
Modified: trunk/scipy/io/matlab/miobase.py
===================================================================
--- trunk/scipy/io/matlab/miobase.py 2009-02-19 02:58:23 UTC (rev 5562)
+++ trunk/scipy/io/matlab/miobase.py 2009-02-19 04:30:03 UTC (rev 5563)
@@ -125,6 +125,60 @@
raise ValueError('Unknown mat file type, version %s' % ret)
+def matdims(arr):
+ ''' Determine equivalent matlab dimensions for given array
+
+ Parameters
+ ----------
+ arr : ndarray
+
+ Returns
+ -------
+ dims : shape as matlab expects
+
+ Examples
+ --------
+ >>> matdims(np.array(1)) # numpy scalar
+ (1, 1)
+ >>> matdims(np.array([1])) # 1d array, 1 element
+ (1, 1)
+ >>> matdims(np.array([1,2])) # 1d array, 2 elements
+ (2, 1)
+ >>> matdims(np.array([[2],[3]])) # 2d array, column vector
+ (2, 1)
+ >>> matdims(np.array([[2,3]])) # 2d array, row vector
+ (1, 2)
+ >>> matdims(np.array([[[2,3]]])) # 3d array, rowish vector
+ (1, 1, 2)
+ >>> matdims(np.array([])) # empty 1d array
+ (0, 0)
+ >>> matdims(np.array([[]])) # empty 2d
+ (0, 0)
+ >>> matdims(np.array([[[]]])) # empty 3d
+ (0, 0, 0)
+
+ Notes
+ -----
+ We had to decide what shape a 1 dimensional array would be.
+ ``np.atleast_2d thinks it is a row vector. The default for a
+ vector in matlab (e.g. ``>> 1:12``) is a row vector.
+
+ Versions of scipy up to and including 0.7 have resulted
+ (accidentally) in 1d arrays being read as column vectors. For the
+ moment, we maintain the same tradition here.
+ '''
+ if arr.size == 0: # empty
+ return (0,) * np.max([arr.ndim, 2])
+ shape = arr.shape
+ if shape == (): # scalar
+ return (1,1)
+ if len(shape) == 1:
+ # 1d array -> column vector. This is what matlab gives from
+ # shape 1,0 if passed in a mat file - the behavior up to and
+ # including scipy 0.7
+ return shape + (1,)
+ return shape
+
class ByteOrder(object):
''' Namespace for byte ordering '''
little_endian = boc.sys_is_le
Modified: trunk/scipy/io/matlab/tests/test_mio.py
===================================================================
--- trunk/scipy/io/matlab/tests/test_mio.py 2009-02-19 02:58:23 UTC (rev 5562)
+++ trunk/scipy/io/matlab/tests/test_mio.py 2009-02-19 04:30:03 UTC (rev 5563)
@@ -24,6 +24,7 @@
from numpy import array
import scipy.sparse as SP
+from scipy.io.matlab.miobase import matdims
from scipy.io.matlab.mio import loadmat, savemat, find_mat_file
from scipy.io.matlab.mio5 import MatlabObject, MatFile5Writer, \
Mat5NumericWriter
@@ -32,15 +33,11 @@
def mlarr(*args, **kwargs):
''' Convenience function to return matlab-compatible 2D array
- Note that matlab writes empty shape as (0,0) - replicated here
'''
arr = np.array(*args, **kwargs)
- if arr.size:
- return np.atleast_2d(arr)
- # empty elements return as shape (0,0)
- return arr.reshape((0,0))
+ arr.shape = matdims(arr)
+ return arr
-
# Define cases to test
theta = np.pi/4*np.arange(9,dtype=float).reshape(1,9)
case_table4 = [
@@ -87,22 +84,22 @@
'expected': {'testonechar': array([u'r'])},
})
# Cell arrays stored as object arrays
-CA = mlarr([
- [], # placeholder, object array constructor wierdness otherwise
- mlarr(1),
- mlarr([1,2]),
- mlarr([1,2,3])], dtype=object).reshape(1,-1)
+CA = mlarr(( # tuple for object array creation
+ [],
+ mlarr([1]),
+ mlarr([[1,2]]),
+ mlarr([[1,2,3]])), dtype=object).reshape(1,-1)
CA[0,0] = array(
[u'This cell contains this string and 3 arrays of increasing length'])
case_table5 = [
{'name': 'cell',
'expected': {'testcell': CA}}]
-CAE = mlarr([
+CAE = mlarr(( # tuple for object array creation
mlarr(1),
mlarr(2),
mlarr([]),
mlarr([]),
- mlarr(3)], dtype=object).reshape(1,-1)
+ mlarr(3)), dtype=object).reshape(1,-1)
case_table5.append(
{'name': 'emptycell',
'expected': {'testemptycell': CAE}})
@@ -194,12 +191,29 @@
case_table5_rt.append(
{'name': 'objectarray',
'expected': {'testobjectarray': np.repeat(MO, 2).reshape(1,2)}})
-''' This test fails - exclude for now
+''' Test fails; consider also savemat('A', {'A':np.array(1, dtype=object)})
case_table5_rt.append(
{'name': 'scalarobject',
- 'expected': {'testscalarobject': mlarr(array([1], dtype=object))}
+ 'expected': {'testscalarobject': mlarr(1, dtype=object)}
})
'''
+
+def types_compatible(var1, var2):
+ ''' Check if types are same or compatible
+
+ 0d numpy scalars are compatible with bare python scalars
+ '''
+ type1 = type(var1)
+ type2 = type(var2)
+ if type1 is type2:
+ return True
+ if type1 is np.ndarray and var1.shape == ():
+ return type(var1.item()) is type2
+ if type2 is np.ndarray and var2.shape == ():
+ return type(var2.item()) is type1
+ return False
+
+
def _check_level(label, expected, actual):
""" Check one level of a potentially nested array """
if SP.issparse(expected): # allow different types of sparse matrices
@@ -210,10 +224,9 @@
decimal = 5)
return
# Check types are as expected
- typex = type(expected)
- typac = type(actual)
- assert_true(typex is typac, \
- "Expected type %s, got %s at %s" % (typex, typac, label))
+ assert_true(types_compatible(expected, actual), \
+ "Expected type %s, got %s at %s" %
+ (type(expected), type(actual), label))
# A field in a record array may not be an ndarray
# A scalar from a record array will be type np.void
if not isinstance(expected,
More information about the Scipy-svn
mailing list