Package topo :: Package misc :: Module inlinec
[hide private]
[frames] | no frames]

Source Code for Module topo.misc.inlinec

  1  """ 
  2  Interface class for inline C/C++ functions.  Based on the SciPy Weave package. 
  3   
  4  Weave (from SciPy) allows programmers to implement Python methods or 
  5  functions using C code written as a string in the Python file.  This 
  6  is generally done to speed up code that would be slow if written 
  7  directly in Python.  Because not all users can be assumed to have a 
  8  working C/C++ compiler, it is crucial for such optimizations to be 
  9  optional.  This file provides an interface for processing the inline 
 10  C/C++ code in a way that can gracefully revert back to the 
 11  unoptimized version when Weave is not available. 
 12   
 13  The fallback is implemented by making use of the way Python allows 
 14  function names to be overwritten, as in these simple examples: 
 15   
 16    def x(y = 5): return y 
 17    def x2(y = 6): return y*y 
 18    print 'x:', x(), 'x2:', x2()  # Result -- x: 5 x2: 36 
 19    x = x2 
 20    print 'x:', x(), 'x2:', x2()  # Result -- x: 36 x2: 36 
 21   
 22  In this file, inline() is overwritten to call inline_weave() if Weave 
 23  is available.  If Weave is not available, inline() will raise a 
 24  NotImplementedError exception.  For a program to be usable without 
 25  Weave, just test inlinec.optimized after defining each optimized 
 26  component, replacing it with a non-optimized equivalent if 
 27  inlinec.optimized is False. 
 28   
 29  For more information on weave, see: 
 30  http://old.scipy.org/documentation/weave/weaveusersguide.html 
 31   
 32  $Id: inlinec.py 11263 2010-07-21 11:37:22Z ceball $ 
 33  """ 
 34   
 35   
 36  import os 
 37  from copy import copy 
 38   
 39  # If import_weave is not defined, or is set to True, will attempt to 
 40  # import weave.  Set import_weave to False if you want to avoid weave 
 41  # altogether, e.g. if your installation is broken. 
 42  import __main__ 
 43  import_weave = __main__.__dict__.get('import_weave',True) 
 44   
 45   
 46  # Variable that will be used to report whether weave was successfully 
 47  # imported (below). 
 48  weave_imported = False 
 49   
 50  # Variable that will be used to report whether simple compilation test 
 51  # was successful. 
 52  compiled = False 
 53   
54 -def inline(*params,**nparams): raise NotImplementedError
55 56 57 58 ########## 59 # Windows: hack to allow weave to work when a user name contains a 60 # space (see 61 # http://thread.gmane.org/gmane.comp.python.scientific.devel/14275) 62 if import_weave: 63 import sys 64 if sys.platform.startswith("win"): 65 try: 66 # catch the initial use of USERNAME by weave 67 original_user = os.environ.get("USERNAME") 68 os.environ["USERNAME"]=original_user.replace(" ","") 69 # now dynamically patch weave and restore USERNAME 70 import scipy.weave.catalog 71 iam = scipy.weave.catalog.whoami().replace(" ","") 72 scipy.weave.catalog.whoami = lambda: iam 73 os.environ["USERNAME"]=original_user 74 except: 75 pass 76 ########## 77 78 try: 79 if import_weave: 80 # We supply weave separately with the source distribution, but 81 # e.g. the ubuntu package uses scipy. 82 try: 83 import weave 84 except ImportError: 85 from scipy import weave 86 87 weave_imported = True 88 89 # Default parameters to add to the inline_weave() call. 90 inline_named_params = { 91 'extra_compile_args':['-O2','-Wno-unused-variable -fomit-frame-pointer','-funroll-loops'], 92 'extra_link_args':['-lstdc++'], 93 'compiler':'gcc', 94 'verbose':0} 95
96 - def inline_weave(*params,**nparams):
97 named_params = copy(inline_named_params) # Make copy of defaults. 98 named_params.update(nparams) # Add newly passed named parameters. 99 weave.inline(*params,**named_params)
100 101 # Overwrites stub definition with full Weave definition 102 inline = inline_weave 103 104 except ImportError: 105 print 'Caution: Unable to import Weave. Will use non-optimized versions of most components.' 106 107 108 if weave_imported: 109 import random 110 try: 111 # to force recompilation each time 112 inline('double x=%s;'%random.random()) 113 compiled = True 114 except: 115 # CB: should maybe display error 116 print 'Caution: Unable to use Weave to compile (no C/C++ compiler?). Will use non-optimized versions of most components.' 117 118 # Flag available for all to use to test whether to use the inline 119 # versions or not. 120 optimized = weave_imported and compiled 121 122 warn_for_each_unoptimized_component = False 123 124
125 -def provide_unoptimized_equivalent(optimized_name, unoptimized_name, local_dict):
126 """ 127 If not using optimization, replace the optimized component with its unoptimized equivalent. 128 129 The objects named by optimized_name and unoptimized_name should be 130 plug-compatible. The local_dict argument should be given the 131 contents of locals(), so that this function can replace the 132 optimized version with the unoptimized one in the namespace from 133 which it has been called. 134 135 As an example, calling this function as:: 136 137 provide_unoptimized_equivalent("sort_opt","sort",locals()) 138 139 is equivalent to putting the following code directly into the 140 calling location:: 141 142 if not optimized: 143 sort_opt = sort 144 print 'module: Inline-optimized components not available; using sort instead of sort_opt.' 145 """ 146 if not optimized: 147 local_dict[optimized_name] = local_dict[unoptimized_name] 148 if warn_for_each_unoptimized_component: 149 print '%s: Inline-optimized components not available; using %s instead of %s.' \ 150 % (local_dict['__name__'], optimized_name, unoptimized_name)
151 152 if not optimized and not warn_for_each_unoptimized_component: 153 print "Note: Inline-optimized components are currently disabled; see topo.misc.inlinec" 154 155 156 # Definitions useful for working with optimized Python code; 157 # prepend to the code for an inlinec call if you want to use them. 158 c_header = """ 159 /* Declaration for interfacing to numpy floats */ 160 typedef double npfloat; 161 162 /* For a given class cls and an attribute attr, defines a variable 163 attr_offset containing the offset of that attribute in the class's 164 __slots__ data structure. */ 165 #define DECLARE_SLOT_OFFSET(attr,cls) \ 166 PyMemberDescrObject *attr ## _descr = (PyMemberDescrObject *)PyObject_GetAttrString(cls,#attr); \ 167 Py_ssize_t attr ## _offset = attr ## _descr->d_member->offset; \ 168 Py_DECREF(attr ## _descr) 169 170 /* After a previous declaration of DECLARE_SLOT_OFFSET, for an 171 instance obj of that class and the given attr, retrieves the value 172 of that attribute from its slot. */ 173 #define LOOKUP_FROM_SLOT_OFFSET(type,attr,obj) \ 174 PyArrayObject *attr ## _obj = *((PyArrayObject **)((char *)obj + attr ## _offset)); \ 175 type *attr = (type *)(attr ## _obj->data) 176 177 /* Same as LOOKUP_FROM_SLOT_OFFSET but ensures the array is contiguous. 178 Must call DECREF_CONTIGUOUS_ARRAY(attr) to release temporary. 179 Does PyArray_FLOAT need to be an argument for this to work with doubles? */ 180 // This code is optimized for contiguous arrays, which are typical, 181 // but we make it work for noncontiguous arrays (e.g. views) by 182 // creating a contiguous copy if necessary. 183 // 184 // CEBALERT: I think there are better alternatives 185 // e.g. PyArray_GETCONTIGUOUS (PyArrayObject*) (PyObject* op) 186 // (p248 of numpybook), which only acts if necessary... 187 // Do we have a case where we know this code is being 188 // called, so that I can test it easily? 189 190 #define CONTIGUOUS_ARRAY_FROM_SLOT_OFFSET(type,attr,obj) \ 191 PyArrayObject *attr ## _obj = *((PyArrayObject **)((char *)obj + attr ## _offset)); \ 192 type *attr = 0; \ 193 PyArrayObject * attr ## _array = 0; \ 194 if(PyArray_ISCONTIGUOUS(weights_obj)) \ 195 attr = (type *)(attr ## _obj->data); \ 196 else { \ 197 attr ## _array = (PyArrayObject*) PyArray_ContiguousFromObject((PyObject*)attr ## _obj,PyArray_FLOAT,2,2); \ 198 attr = (type *) attr ## _array->data; \ 199 } 200 201 #define DECREF_CONTIGUOUS_ARRAY(attr) \ 202 if(attr ## _array != 0) \ 203 Py_DECREF(attr ## _array) 204 205 206 207 #define UNPACK_FOUR_TUPLE(type,i1,i2,i3,i4,tuple) \ 208 type i1 = *tuple++; \ 209 type i2 = *tuple++; \ 210 type i3 = *tuple++; \ 211 type i4 = *tuple 212 """ 213 214 # Simple test 215 if __name__ == '__main__': 216 inline('printf("Hello World!!\\n");') 217