diff options
Diffstat (limited to 'numpy/testing/utils.py')
-rw-r--r-- | numpy/testing/utils.py | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/numpy/testing/utils.py b/numpy/testing/utils.py new file mode 100644 index 000000000..8e01afb56 --- /dev/null +++ b/numpy/testing/utils.py @@ -0,0 +1,238 @@ +""" +Utility function to facilitate testing. +""" + +import os +import sys +import operator + +__all__ = ['assert_equal', 'assert_almost_equal','assert_approx_equal', + 'assert_array_equal', 'assert_array_less', + 'assert_array_almost_equal', 'jiffies', 'memusage', 'rand', + 'runstring'] + +def rand(*args): + """Returns an array of random numbers with the given shape. + + This only uses the standard library, so it is useful for testing purposes. + """ + import random + from numpy.core import zeros, float64 + results = zeros(args, float64) + f = results.flat + for i in range(len(f)): + f[i] = random.random() + return results + +if sys.platform[:5]=='linux': + def jiffies(_proc_pid_stat = '/proc/%s/stat'%(os.getpid()), + _load_time=[]): + """ Return number of jiffies (1/100ths of a second) that this + process has been scheduled in user mode. See man 5 proc. """ + import time + if not _load_time: + _load_time.append(time.time()) + try: + f=open(_proc_pid_stat,'r') + l = f.readline().split(' ') + f.close() + return int(l[13]) + except: + return int(100*(time.time()-_load_time[0])) + + def memusage(_proc_pid_stat = '/proc/%s/stat'%(os.getpid())): + """ Return virtual memory size in bytes of the running python. + """ + try: + f=open(_proc_pid_stat,'r') + l = f.readline().split(' ') + f.close() + return int(l[22]) + except: + return +else: + # os.getpid is not in all platforms available. + # Using time is safe but inaccurate, especially when process + # was suspended or sleeping. + def jiffies(_load_time=[]): + """ Return number of jiffies (1/100ths of a second) that this + process has been scheduled in user mode. [Emulation with time.time]. """ + import time + if not _load_time: + _load_time.append(time.time()) + return int(100*(time.time()-_load_time[0])) + def memusage(): + """ Return memory usage of running python. [Not implemented]""" + raise NotImplementedError + +if os.name=='nt' and sys.version[:3] > '2.3': + # Code "stolen" from enthought/debug/memusage.py + def GetPerformanceAttributes(object, counter, instance = None, + inum=-1, format = None, machine=None): + # NOTE: Many counters require 2 samples to give accurate results, + # including "% Processor Time" (as by definition, at any instant, a + # thread's CPU usage is either 0 or 100). To read counters like this, + # you should copy this function, but keep the counter open, and call + # CollectQueryData() each time you need to know. + # See http://msdn.microsoft.com/library/en-us/dnperfmo/html/perfmonpt2.asp + # My older explanation for this was that the "AddCounter" process forced + # the CPU to 100%, but the above makes more sense :) + import win32pdh + if format is None: format = win32pdh.PDH_FMT_LONG + path = win32pdh.MakeCounterPath( (machine,object,instance, None, inum,counter) ) + hq = win32pdh.OpenQuery() + try: + hc = win32pdh.AddCounter(hq, path) + try: + win32pdh.CollectQueryData(hq) + type, val = win32pdh.GetFormattedCounterValue(hc, format) + return val + finally: + win32pdh.RemoveCounter(hc) + finally: + win32pdh.CloseQuery(hq) + + def memusage(processName="python", instance=0): + # from win32pdhutil, part of the win32all package + import win32pdh + return GetPerformanceAttributes("Process", "Virtual Bytes", + processName, instance, + win32pdh.PDH_FMT_LONG, None) + +def build_err_msg(arrays, err_msg, header='Items are not equal:', + verbose=True, + names=('ACTUAL', 'DESIRED')): + msg = ['\n' + header] + if err_msg: + if err_msg.find('\n') == -1 and len(err_msg) < 79-len(header): + msg = [msg[0] + ' ' + err_msg] + else: + msg.append(err_msg) + if verbose: + for i, a in enumerate(arrays): + try: + r = repr(a) + except: + r = '[repr failed]' + if r.count('\n') > 3: + r = '\n'.join(r.splitlines()[:3]) + r += '...' + msg.append(' %s: %s' % (names[i], r)) + return '\n'.join(msg) + +def assert_equal(actual,desired,err_msg='',verbose=True): + """ Raise an assertion if two items are not + equal. I think this should be part of unittest.py + """ + if isinstance(desired, dict): + assert isinstance(actual, dict), repr(type(actual)) + assert_equal(len(actual),len(desired),err_msg,verbose) + for k,i in desired.items(): + assert actual.has_key(k), repr(k) + assert_equal(actual[k], desired[k], 'key=%r\n%s' % (k,err_msg), verbose) + return + if isinstance(desired, (list,tuple)) and isinstance(actual, (list,tuple)): + assert_equal(len(actual),len(desired),err_msg,verbose) + for k in range(len(desired)): + assert_equal(actual[k], desired[k], 'item=%r\n%s' % (k,err_msg), verbose) + return + from numpy.core import ndarray + if isinstance(actual, ndarray) or isinstance(desired, ndarray): + return assert_array_equal(actual, desired, err_msg) + msg = build_err_msg([actual, desired], err_msg, verbose=verbose) + assert desired == actual, msg + +def assert_almost_equal(actual,desired,decimal=7,err_msg='',verbose=True): + """ Raise an assertion if two items are not equal. + + I think this should be part of unittest.py + + The test is equivalent to abs(desired-actual) < 0.5 * 10**(-decimal) + """ + from numpy.core import ndarray + if isinstance(actual, ndarray) or isinstance(desired, ndarray): + return assert_array_almost_equal(actual, desired, decimal, err_msg) + msg = build_err_msg([actual, desired], err_msg, verbose=verbose) + assert round(abs(desired - actual),decimal) == 0, msg + + +def assert_approx_equal(actual,desired,significant=7,err_msg='',verbose=True): + """ Raise an assertion if two items are not + equal. I think this should be part of unittest.py + Approximately equal is defined as the number of significant digits + correct + """ + import math + actual, desired = map(float, (actual, desired)) + if desired==actual: + return + # Normalized the numbers to be in range (-10.0,10.0) + scale = float(pow(10,math.floor(math.log10(0.5*(abs(desired)+abs(actual)))))) + try: + sc_desired = desired/scale + except ZeroDivisionError: + sc_desired = 0.0 + try: + sc_actual = actual/scale + except ZeroDivisionError: + sc_actual = 0.0 + msg = build_err_msg([actual, desired], err_msg, + header='Items are not equal to %d significant digits:' % + significant, + verbose=verbose) + assert math.fabs(sc_desired - sc_actual) < pow(10.,-(significant-1)), msg + +def assert_array_compare(comparison, x, y, err_msg='', verbose=True, + header=''): + from numpy.core import asarray + x = asarray(x) + y = asarray(y) + try: + cond = (x.shape==() or y.shape==()) or x.shape == y.shape + if not cond: + msg = build_err_msg([x, y], + err_msg + + '\n(shapes %s, %s mismatch)' % (x.shape, + y.shape), + verbose=verbose, header=header, + names=('x', 'y')) + assert cond, msg + val = comparison(x,y) + if isinstance(val, bool): + cond = val + reduced = [0] + else: + reduced = val.ravel() + cond = reduced.all() + reduced = reduced.tolist() + if not cond: + match = 100-100.0*reduced.count(1)/len(reduced) + msg = build_err_msg([x, y], + err_msg + + '\n(mismatch %s%%)' % (match,), + verbose=verbose, header=header, + names=('x', 'y')) + assert cond, msg + except ValueError: + msg = build_err_msg([x, y], err_msg, verbose=verbose, header=header, + names=('x', 'y')) + raise ValueError(msg) + +def assert_array_equal(x, y, err_msg='', verbose=True): + assert_array_compare(operator.__eq__, x, y, err_msg=err_msg, + verbose=verbose, header='Arrays are not equal') + +def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True): + from numpy.core import around + def compare(x, y): + return around(abs(x-y),decimal) <= 10.0**(-decimal) + assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose, + header='Arrays are not almost equal') + +def assert_array_less(x, y, err_msg='', verbose=True): + assert_array_compare(operator.__lt__, x, y, err_msg=err_msg, + verbose=verbose, + header='Arrays are not less-ordered') + +def runstring(astr, dict): + exec astr in dict |