[Scipy-svn] r4509 - trunk/scipy/sandbox/mkufunc
scipy-svn at scipy.org
scipy-svn at scipy.org
Mon Jun 30 20:36:02 EDT 2008
Author: ilan
Date: 2008-06-30 19:36:02 -0500 (Mon, 30 Jun 2008)
New Revision: 4509
Removed:
trunk/scipy/sandbox/mkufunc/mkufunc.py
Log:
Moved into mkufunc/
Deleted: trunk/scipy/sandbox/mkufunc/mkufunc.py
===================================================================
--- trunk/scipy/sandbox/mkufunc/mkufunc.py 2008-07-01 00:35:15 UTC (rev 4508)
+++ trunk/scipy/sandbox/mkufunc/mkufunc.py 2008-07-01 00:36:02 UTC (rev 4509)
@@ -1,337 +0,0 @@
-""" mkufunc (make U function)
-
-
-Author: Ilan Schnell (with help from Travis Oliphant and Eric Jones)
-"""
-import sys
-import re
-import os, os.path
-import cStringIO
-import hashlib
-from types import FunctionType
-
-import numpy
-from scipy import weave
-
-
-verbose = 0
-
-def func_hash(f, salt=None):
- """ Return a MD5 hash for a function object as string.
- """
- co = f.func_code
- return hashlib.md5(co.co_code + repr(co.co_names) + repr(salt)
- ).hexdigest()
-
-
-def translate(f, argtypes):
- """ Return pypy's C output for a given function and argument types.
-
- The cache files are in weave's directory.
- """
- cache_file_name = os.path.join(weave.catalog.default_dir(),
- 'pypy_%s.c' % func_hash(f, salt=argtypes))
- try:
- return open(cache_file_name).read()
-
- except IOError:
- from interactive import Translation
-
- t = Translation(f, backend='c')
- t.annotate(argtypes)
- t.source()
-
- os.rename(t.driver.c_source_filename, cache_file_name)
-
- return translate(f, argtypes)
-
-
-class Ctype:
- def __init__(self, npy, c):
- self.npy = npy
- self.c = c
-
-typedict = {
- int: Ctype('NPY_LONG', 'long' ),
- float: Ctype('NPY_DOUBLE', 'double'),
-}
-
-
-class Cfunc(object):
- """ C compiled python functions
-
- >>> def sqr(x):
- ... return x * x
-
- >>> signature = [int, int] # only the input arguments are used here
-
- compilation is done upon initialization
- >>> x = Cfunc(sqr, signature, 123)
- <IGNORE_OUTPUT>
- >>> x.nin # number of input arguments
- 1
- >>> x.nout # number of output arguments (must be 1 for now)
- 1
- >>> x.sig
- [<type 'int'>, <type 'int'>]
-
- Attributes:
- f -- the Python function object
- n -- id number
- sig -- signature
- nin -- number of input arguments
- nout -- number of output arguments
- cname -- name of the C function
-
- Methods:
-
- decl() -- returns the C declaration for the function
- cfunc() -- returns the C function (as string)
- ufunc_support_code()
- -- generate the C support code to make this
- function part work with PyUFuncGenericFunction
- """
- def __init__(self, f, signature, n):
- self.f = f
- self.n = n
- self.sig = signature
- self.nin = f.func_code.co_argcount
- self.nout = len(self.sig) - self.nin
- assert self.nout == 1 # for now
-
- src = translate(f, signature[:self.nin])
-
- self._prefix = 'f%i_' % self.n
- self._allCsrc = src.replace('pypy_', self._prefix + 'pypy_')
- self.cname = self._prefix + 'pypy_g_' + f.__name__
-
- def cfunc(self):
- p = re.compile(r'^\w+[*\s\w]+' + self.cname +
- r'\s*\([^)]*\)\s*\{.*?[\n\r]\}[\n\r]',
- re.DOTALL | re.MULTILINE | re.VERBOSE)
-
- found = p.findall(self._allCsrc)
- assert len(found) == 1
- res = found[0]
- res = res.replace(self._prefix + 'pypy_g_ll_math_ll_math_', '')
- return 'inline ' + res + '\n'
-
- def ufunc_support_code(self):
- # Unfortunately the code in here is very hard to read.
- # In order to make the code clearer, one would need a real template
- # engine link Cheetah (http://cheetahtemplate.org/).
- # However, somehting like that would be too much overhead for scipy.
- n = self.n
- nin = self.nin
- cname = self.cname
-
- def varname(i):
- return chr(i + ord('a'))
-
- declargs = ', '.join('%s %s' % (typedict[self.sig[i]].c, varname(i))
- for i in xrange(self.nin))
-
- args = ', '.join(varname(i) for i in xrange(self.nin))
-
- isn_steps = '\n\t'.join('npy_intp is%i = steps[%i];' % (i, i)
- for i in xrange(self.nin))
-
- ipn_args = '\n\t'.join('char *ip%i = args[%i];' % (i, i)
- for i in xrange(self.nin))
-
- body1d_in = '\n\t\t'.join('%s *in%i = (%s *)ip%i;' %
- (2*(typedict[self.sig[i]].c, i))
- for i in xrange(self.nin))
-
- body1d_add = '\n\t\t'.join('ip%i += is%i;' % (i, i)
- for i in xrange(self.nin))
-
- ptrargs = ', '.join('*in%i' % i for i in xrange(self.nin))
-
- rettype = typedict[self.sig[-1]].c
-
- return '''
-static %(rettype)s wrap_%(cname)s(%(declargs)s)
-{
- return %(cname)s(%(args)s);
-}
-
-typedef %(rettype)s Func_%(n)i(%(declargs)s);
-
-static void
-PyUFunc_%(n)i(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
-{
- npy_intp i, n;
- %(isn_steps)s
- npy_intp os = steps[%(nin)s];
- %(ipn_args)s
- char *op = args[%(nin)s];
- Func_%(n)i *f = (Func_%(n)i *) func;
- n = dimensions[0];
-
- for(i = 0; i < n; i++) {
- %(body1d_in)s
- %(rettype)s *out = (%(rettype)s *)op;
-
- *out = (%(rettype)s) f(%(ptrargs)s);
-
- %(body1d_add)s
- op += os;
- }
-}
-''' % locals()
-
-
-def support_code(cfuncs):
- """ Given a list of Cfunc instances, return the support code for weave.
- """
- acc = cStringIO.StringIO()
-
- acc.write('/********************* start pypy_head.h **************/\n\n')
- acc.write(open(os.path.join(os.path.dirname(__file__),
- 'pypy_head.h')).read())
- acc.write('/********************** end pypy_head.h ****************/\n\n')
-
- for cf in cfuncs:
- acc.write(cf.cfunc())
- acc.write(cf.ufunc_support_code())
-
- fname = cfuncs[0].f.__name__
-
- pyufuncs = ''.join('\tPyUFunc_%i,\n' % cf.n for cf in cfuncs)
-
- data = ''.join('\t(void *) wrap_%s,\n' % cf.cname for cf in cfuncs)
-
- types = ''.join('\t%s /* %i */\n' %
- (''.join(typedict[t].npy + ', ' for t in cf.sig), cf.n)
- for cf in cfuncs)
-
- acc.write('''
-static PyUFuncGenericFunction %(fname)s_functions[] = {
-%(pyufuncs)s};
-
-static void *%(fname)s_data[] = {
-%(data)s};
-
-static char %(fname)s_types[] = {
-%(types)s};
-''' % locals())
-
- if verbose:
- print '------------------ start support_code -----------------'
- print acc.getvalue()
- print '------------------- end support_code ------------------'
-
- return acc.getvalue()
-
-
-def code(f, signatures):
- """ Return the code for weave.
- """
- nin = f.func_code.co_argcount
- ntypes = len(signatures)
- fname = f.__name__
- fhash = func_hash(f)
-
- res = '''
-import_ufunc();
-
-/****************************************************************************
-** function name: %(fname)s
-** signatures: %(signatures)r
-** fhash: %(fhash)s
-*****************************************************************************/
-
-return_val = PyUFunc_FromFuncAndData(
- %(fname)s_functions,
- %(fname)s_data,
- %(fname)s_types,
- %(ntypes)i, /* ntypes */
- %(nin)i, /* nin */
- 1, /* nout */
- PyUFunc_None, /* identity */
- "%(fname)s", /* name */
- "UFunc created by mkufunc", /* doc */
- 0);
-''' % locals()
-
- if verbose:
- print '---------------------- start code ---------------------'
- print res
- print '----------------------- end code ----------------------'
-
- return res
-
-
-def genufunc(f, signatures):
- """ Return the Ufunc Python object for given function and signatures.
- """
- if len(signatures) == 0:
- raise ValueError("At least one signature needed")
-
- signatures.sort(key=lambda sig: [numpy.dtype(typ).num for typ in sig])
-
- cfuncs = [Cfunc(f, sig, n) for n, sig in enumerate(signatures)]
-
- ufunc_info = weave.base_info.custom_info()
- ufunc_info.add_header('"numpy/ufuncobject.h"')
-
- return weave.inline(code(f, signatures),
- verbose=verbose,
- support_code=support_code(cfuncs),
- customize=ufunc_info)
-
-
-def mkufunc(arg0=[float]):
- """ The actual API function, for use in decorator function.
-
- """
- class Compile(object):
-
- def __init__(self, f):
- nin = f.func_code.co_argcount
- nout = 1
- for i, sig in enumerate(signatures):
- if isinstance(sig, tuple):
- pass
- elif sig in typedict.keys():
- signatures[i] = (nin + nout) * (sig,)
- else:
- raise TypeError("no match for %r" % sig)
-
- for sig in signatures:
- assert isinstance(sig, tuple)
- if len(sig) != nin + nout:
- raise TypeError("signature %r does not match the "
- "number of args of function %s" %
- (sig, f.__name__))
- for t in sig:
- if t not in typedict.keys():
- raise TypeError("no match for %r" % t)
-
- self.ufunc = genufunc(f, signatures)
-
- def __call__(self, *args):
- return self.ufunc(*args)
-
- if isinstance(arg0, FunctionType):
- f = arg0
- signatures = [float]
- return Compile(f)
-
- elif isinstance(arg0, list):
- signatures = arg0
- return Compile
-
- elif arg0 in typedict.keys():
- signatures = [arg0]
- return Compile
-
- else:
- raise TypeError("first argument has to be a function, a type, or "
- "a list of signatures")
-
-
-if __name__ == '__main__':
- import doctest
- doctest.testmod()
More information about the Scipy-svn
mailing list