[Scipy-svn] r2401 - in trunk/Lib/io: . tests
scipy-svn at scipy.org
scipy-svn at scipy.org
Tue Dec 12 20:30:34 EST 2006
Author: matthew.brett at gmail.com
Date: 2006-12-12 19:30:27 -0600 (Tue, 12 Dec 2006)
New Revision: 2401
Modified:
trunk/Lib/io/recaster.py
trunk/Lib/io/tests/test_recaster.py
Log:
Cleaning up, bugfixes to recaster class
Modified: trunk/Lib/io/recaster.py
===================================================================
--- trunk/Lib/io/recaster.py 2006-12-12 19:10:16 UTC (rev 2400)
+++ trunk/Lib/io/recaster.py 2006-12-13 01:30:27 UTC (rev 2401)
@@ -59,11 +59,6 @@
are not in the list of ATs.
'''
- _sctype_trans = {'complex': 'c', 'c': 'c',
- 'float': 'f', 'f': 'f',
- 'int': 'i', 'i': 'i',
- 'uint': 'u', 'u': 'u'}
-
_sctype_attributes = sctype_attributes()
def __init__(self, sctype_list=None,
@@ -71,6 +66,7 @@
downcast_fp_to_int = True,
downcast_int_to_int = True,
upcast_int_to_fp = True,
+ upcast_fp_to_int = True,
sctype_tols=None):
''' Set types for which we are attempting to downcast
@@ -85,6 +81,8 @@
smaller of same type
upcast_int_to_fp - if True, tries to upcast integers that could not
be downcast to floating point type
+ upcast_fp_to_int - if True, tries to upcast floating point arrays
+ that cannot be downcast, to integers
sctype_tols - dictionary key datatype, values rtol, tol
to specify tolerances for checking near equality in
downcasting
@@ -101,6 +99,7 @@
self.downcast_fp_to_int = downcast_fp_to_int
self.downcast_int_to_int = downcast_int_to_int
self.upcast_int_to_fp = upcast_int_to_fp
+ self.upcast_fp_to_int = upcast_fp_to_int
# Tolerances
if sctype_tols is not None:
self.sctype_tols.update(sctype_tols)
@@ -142,21 +141,17 @@
'atol': F.tiny}
return t_dict
- def sctypes_by_size(self, sctype):
+ def sctypes_by_size(self, kind):
''' Returns storage size ordered list of entries of scalar type sctype
Input
- sctype - one of "complex" or "c", "float" or "f" ,
- "int" or "i", "uint" or "u"
+ kind - one of "c", "f", "i" or "u"
+ (for complex, float, integer, unsigned integer)
'''
- try:
- sctype = self._sctype_trans[sctype]
- except KeyError:
- raise TypeError, 'Did not recognize sctype %s' % sctype
D = []
for t in self.sctype_list:
dt = dtype(t)
- if dt.kind == sctype:
+ if dt.kind == kind:
D.append([t, dt.itemsize])
D.sort(lambda x, y: cmp(y[1], x[1]))
return D
@@ -212,10 +207,12 @@
break
return out_t
- def tols_from_sctype(self, sctype):
- ''' Return rtol and atol for sctype '''
- tols = self.sctype_tols[sctype]
- return tols['rtol'], tols['atol']
+ def all_close(self, arr1, arr2):
+ ''' True if arr1 arr2 close with tols for arr1 '''
+ tols = self.sctype_tols[arr1.dtype.type]
+ return allclose(arr1, arr2,
+ rtol=tols['rtol'],
+ atol=tols['atol'])
def arr_if_valid(self, arr):
''' Returns array if of valid sctype, None otherwise '''
@@ -223,35 +220,28 @@
return None
return arr
- def smallest_same_kind(self, arr):
+ def smallest_of_kind(self, arr, kind=None, max_size=None):
''' Return arr maybe downcast to same kind, smaller storage
+ Inputs
+ arr - array to possibly downcast
+ kind - kind of array to downcast within
+ (if None (default) use arr.dtype.kind)
+ max_size - maximum size of sctype to return (in bytes)
+ (if None, set to arr.dtype.itemsize-1)
If arr cannot be downcast within given tolerances, then:
return arr if arr is in list of acceptable types, otherwise
return None
'''
dtp = arr.dtype
- dti = dtp.itemsize
- sctypes = self.sized_sctypes[dtp.kind]
- sctypes = [t[0] for i, t in enumerate(sctypes) if t[1] < dti]
- return self._smallest_from_sctypes(arr, sctypes)
-
- def _smallest_from_sctypes(self, arr, sctypes):
- ''' Returns array recast to smallest possible type from list
-
- Inputs
- arr - array to recast
- sctypes - list of scalar types to try
-
- sctypes is expected to be ordered by size with largest first,
- and to all be of the same type. It would not usually be
- sensible to use this routine for integers (see
- smallest_int_sctype method)
-
- Returns None if no recast is within tolerance
- '''
- sct = arr.dtype.type
- rtol, atol = self.tols_from_sctype(sct)
+ if kind is None:
+ kind = dtp.kind
+ if max_size is None:
+ max_size = dtp.itemsize-1
+ sctypes = self.sized_sctypes[kind]
+ sctypes = [t[0] for i, t in enumerate(sctypes) if t[1] <= max_size]
+ tols = self.sctype_tols[dtp.type]
+ rtol, atol = tols['rtol'], tols['atol']
ret_arr = arr
for T in sctypes:
test_arr = arr.astype(T)
@@ -279,94 +269,112 @@
sz = tsz
return sct
- def downcast(self, arr):
- dtk = arr.dtype.kind
- if dtk == 'c':
- ret = self.downcast_complex(arr)
- elif dtk == 'f':
- ret = self.downcast_float(arr)
- elif dtk in ('u', 'i'):
- ret = self.downcast_integer(arr)
- else:
- raise TypeError, 'Do not recognize array kind %s' % dtk
- if ret is None:
- raise ValueError, 'Could not downcast array within precision'
- return ret
-
- def downcast_complex(self, arr):
- ''' Downcasts complex array to smaller type if possible '''
- # can we downcast to float?
- if self.downcast_fp_to_fp:
- dt = arr.dtype
- dti = ceil(dt.itemsize / 2)
- sctypes = self.sized_sctypes['f']
- flts = [t[0] for i, t in enumerate(sctypes) if t[1] <= dti]
- if flts: # There are smaller floats to try
- test_arr = arr.astype(flts[0])
- rtol, atol = self.tols_from_sctype(dt.type)
- if allclose(arr, test_arr, rtol, atol):
- arr = test_arr
- # try downcasting to int or another complex type
- return self.downcast_to_int_or_same(arr)
-
- def downcast_to_int_or_same(self, arr):
- ''' Downcast to integer or smaller of same kind '''
- # Try integer
- if self.downcast_fp_to_int:
- test_arr = self.downcast_integer(arr)
- rtol, atol = self.tols_from_sctype(arr.dtype.type)
- if allclose(arr, test_arr, rtol, atol):
- return test_arr
- # Otherwise descend the types of same kind
- if self.downcast_fp_to_fp:
- return self.smallest_same_kind(arr)
- return self.arr_if_valid(arr)
-
- downcast_float = downcast_to_int_or_same
+ def cast_to_integer(self, arr):
+ ''' Casts arr to smallest integer containing range
- def downcast_integer(self, arr):
- ''' Downcasts arr to integer
-
Returns None if range of arr cannot be contained in acceptable
integer types
'''
- if not self.downcast_int_to_int:
- return arr_if_valid(arr)
mx = amax(arr)
mn = amin(arr)
idt = self.smallest_int_sctype(mx, mn)
- if idt:
+ if idt is not None:
return arr.astype(idt)
return None
- def recast(self, arr):
- ''' Try arr downcast, upcast if necesary to get compatible type '''
- try:
- return self.downcast(arr)
- except ValueError:
- pass
- dt = arr.dtype
+ def downcast_or_none(self, arr):
+ ''' Downcast array to smaller or same type
+
+ If cannot find smaller type within tolerance,
+ return array if is already valid type, otherwise None
+ '''
+ dtp = arr.dtype
+ dtk = dtp.kind
+ dti = dtp.itemsize
+ if dtk in ('c', 'f'):
+ if self.downcast_fp_to_int:
+ test_arr = self.cast_to_integer(arr)
+ if test_arr is not None:
+ if self.all_close(arr, test_arr):
+ return test_arr
+ if self.downcast_fp_to_fp:
+ if dtk == 'c':
+ # Try downcasting to float
+ max_size = ceil(dti / 2.0)
+ test_arr = self.smallest_of_kind(arr, 'f', max_size)
+ if test_arr is not None:
+ return test_arr
+ test_arr = self.smallest_of_kind(arr)
+ if test_arr is not None:
+ return test_arr
+ elif dtk in ('u', 'i'):
+ if self.downcast_int_to_int:
+ test_arr = self.cast_to_integer(arr)
+ if test_arr is not None:
+ if test_arr.dtype.itemsize <= dti:
+ return test_arr
+ else:
+ raise TypeError, 'Do not recognize array kind %s' % dtk
+ return self.arr_if_valid(arr)
+
+
+ def recast_or_none(self, arr):
+ ''' Recast array to type in type list
+
+ If cannot find smaller type within tolerance, by downcasting,
+ and array not of valid type already, then try larger
+ types. If none of these return an array within tolerance,
+ return None
+ '''
+ test_arr = self.downcast_or_none(arr)
+ if test_arr is not None:
+ return test_arr
# Could not downcast, arr dtype not in known list
- # Try upcast to larger dtype of same kind
- sct = dt.type
- udt = self.capable_sctype[sct]
- if udt is not None:
- return arr.astype(udt)
- # Could be an integer type that we have not tried
- # to downcast
- if not self.downcast_int_to_int and dt.kind in ('u', 'i'):
- arr = self.downcast_integer(arr)
- if arr is not None:
- return arr
- # We are stuck for floats and complex now
- # Can try casting integers to floats
- if self.upcast_int_to_fp and dt.kind in ('i', 'u'):
- sctypes = self.sized_sctypes['f']
- arr = self._smallest_from_sctypes(arr, sctypes)
- if arr is not None:
- return arr
- raise ValueError, 'Could not recast array within precision'
+ dtp = arr.dtype
+ dtk = dtp.kind
+ sct = dtp.type
+ if dtk in ('c', 'f'):
+ # Try upcast to larger dtype of same kind
+ udt = self.capable_sctype[sct]
+ if udt is not None:
+ return arr.astype(udt)
+ # Try casting to an integer
+ if self.upcast_fp_to_int:
+ test_arr = self.cast_to_integer(arr)
+ if test_arr is not None:
+ if self.all_close(arr, test_arr):
+ return test_arr
+ else: # integer types
+ # try casting to any possible integer type
+ test_arr = self.cast_to_integer(arr)
+ if test_arr is not None:
+ return test_arr
+ # Can try casting integers to floats
+ if self.upcast_int_to_fp:
+ flts = self._sized_sctypes['f']
+ if flts:
+ flt_arr = arr.astype(flts[0])
+ if self.all_close(arr, flt_arr):
+ if self.downcast_fp_to_fp:
+ max_size = flt_arr.dtype.itemsize - 1
+ test_arr = self.smallest_of_kind(arr, 'f', max_size)
+ if test_arr is not None:
+ return test_arr
+ return flt_arr
+ return None
+
+ def downcast(self, arr):
+ ret = self.downcast_or_none(arr)
+ if ret is None:
+ raise TypeError, 'Cannot downcast array within tolerance'
+ return ret
+ def recast(self, arr):
+ ret = self.recast_or_none(arr)
+ if ret is None:
+ raise TypeError, 'Cannot recast array within tolerance'
+ return ret
+
def recast_best_sctype(self, arr):
''' Recast array, return closest sctype to original
Modified: trunk/Lib/io/tests/test_recaster.py
===================================================================
--- trunk/Lib/io/tests/test_recaster.py 2006-12-12 19:10:16 UTC (rev 2400)
+++ trunk/Lib/io/tests/test_recaster.py 2006-12-13 01:30:27 UTC (rev 2401)
@@ -29,14 +29,13 @@
F = N.finfo(T)
R = Recaster(sctype_tols={T: {'rtol': F.eps*2, 'atol': F.tiny*2, 'silly': 'silly text'}})
assert tols != R.sctype_tols, 'Tols dictionary not set correctly'
- r, a = R.tols_from_sctype(T)
- assert r == F.eps*2, 'Rtol not correctly set'
- assert a == F.tiny*2, 'Atol not correctly set'
+ assert R.sctype_tols[T]['rtol'] == F.eps*2, 'Rtol not correctly set'
+ assert R.sctype_tols[T]['atol'] == F.tiny*2, 'Atol not correctly set'
# Sctype size lists
# Integer sizes
# Cabable types
- def test_smallest_same_kind(self):
+ def test_smallest_of_kind(self):
R = self.recaster
value = 1
# smallest same kind
@@ -54,7 +53,7 @@
expect_none = ((req_type is None) or
((tdtsz <= rdtsz) and not ok_T))
A = N.array(value, T)
- C = R.smallest_same_kind(A)
+ C = R.smallest_of_kind(A)
if expect_none:
assert C is None, 'Expecting None for %s' % T
else:
@@ -98,7 +97,6 @@
R = self.recaster
for T in (N.complex128, N.complex64,
N.float64, N.uint64):
- B = R.downcast(N.array(value, T))
+ B = R.downcast_or_none(N.array(value, T))
assert B is not None, 'Got None for %s' % T
assert B.dtype.type == N.int32
-
More information about the Scipy-svn
mailing list