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
40
41
42 import __main__
43 import_weave = __main__.__dict__.get('import_weave',True)
44
45
46
47
48 weave_imported = False
49
50
51
52 compiled = False
53
54 -def inline(*params,**nparams): raise NotImplementedError
55
56
57
58
59
60
61
62 if import_weave:
63 import sys
64 if sys.platform.startswith("win"):
65 try:
66
67 original_user = os.environ.get("USERNAME")
68 os.environ["USERNAME"]=original_user.replace(" ","")
69
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
81
82 try:
83 import weave
84 except ImportError:
85 from scipy import weave
86
87 weave_imported = True
88
89
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
100
101
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
112 inline('double x=%s;'%random.random())
113 compiled = True
114 except:
115
116 print 'Caution: Unable to use Weave to compile (no C/C++ compiler?). Will use non-optimized versions of most components.'
117
118
119
120 optimized = weave_imported and compiled
121
122 warn_for_each_unoptimized_component = False
123
124
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
157
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
215 if __name__ == '__main__':
216 inline('printf("Hello World!!\\n");')
217