| 1 |
# svpmc: Stochastic Volatility Inference via Population Monte Carlo |
|---|
| 2 |
# |
|---|
| 3 |
# Copyright (C) 2008 by Edwin A. Suominen, http://www.eepatents.com |
|---|
| 4 |
# |
|---|
| 5 |
# This program is free software; you can redistribute it and/or modify it under |
|---|
| 6 |
# the terms of the GNU General Public License as published by the Free Software |
|---|
| 7 |
# Foundation; either version 2 of the License, or (at your option) any later |
|---|
| 8 |
# version. |
|---|
| 9 |
# |
|---|
| 10 |
# This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 11 |
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|---|
| 12 |
# FOR A PARTICULAR PURPOSE. See the file COPYING for more details. |
|---|
| 13 |
# |
|---|
| 14 |
# You should have received a copy of the GNU General Public License along with |
|---|
| 15 |
# this program; if not, write to the Free Software Foundation, Inc., 51 |
|---|
| 16 |
# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|---|
| 17 |
|
|---|
| 18 |
""" |
|---|
| 19 |
Convenience class for doing inline C with SciPy.weave. |
|---|
| 20 |
|
|---|
| 21 |
You can import from this module instead of scipy.weave. Then you get the |
|---|
| 22 |
convenience class L{Weaver} in addition to the good stuff in scipy.weave. |
|---|
| 23 |
""" |
|---|
| 24 |
|
|---|
| 25 |
import inspect, re |
|---|
| 26 |
from pkg_resources import resource_string |
|---|
| 27 |
from scipy.weave import * |
|---|
| 28 |
from scipy.weave.base_info import custom_info |
|---|
| 29 |
|
|---|
| 30 |
|
|---|
| 31 |
class my_info(custom_info): |
|---|
| 32 |
_extra_compile_args = ['-w', '-O3', '-march=native'] |
|---|
| 33 |
__macros = [ |
|---|
| 34 |
# Access an element i of a 1-D array whose pointer is pa |
|---|
| 35 |
'PA1(pa,i)', |
|---|
| 36 |
"*(pa + i)", |
|---|
| 37 |
|
|---|
| 38 |
# Access an element i of a 1-D array whose pointer is pa in a structure |
|---|
| 39 |
# whose pointer is s |
|---|
| 40 |
'SPA1(s,pa,i)', |
|---|
| 41 |
"*(s->pa + i)", |
|---|
| 42 |
|
|---|
| 43 |
# Access an element i, j of a 2-D Numpy array object whose pointer is |
|---|
| 44 |
# ppa |
|---|
| 45 |
'PP2(ppa,i,j)', |
|---|
| 46 |
"(*((double*)(ppa->data + (i)*ppa->strides[0] + (j)*ppa->strides[1])))", |
|---|
| 47 |
|
|---|
| 48 |
# Access an element i of a 1-D Numpy array object whose pointer is ppa |
|---|
| 49 |
# in a structure whose pointer is s |
|---|
| 50 |
'SPP1(s,ppa,i)', |
|---|
| 51 |
"(*((double*)(s->ppa->data + (i)*s->ppa->strides[0])))", |
|---|
| 52 |
|
|---|
| 53 |
# Access an element i, j of a 2-D Numpy array object whose pointer is |
|---|
| 54 |
# ppa in a structure whose pointer is s |
|---|
| 55 |
'SPP2(s,ppa,i,j)', |
|---|
| 56 |
"(*((double*)(s->ppa->data + "+\ |
|---|
| 57 |
"(i)*s->ppa->strides[0] + (j)*s->ppa->strides[1])))", |
|---|
| 58 |
] |
|---|
| 59 |
|
|---|
| 60 |
def __init__(self): |
|---|
| 61 |
k = 0 |
|---|
| 62 |
macros = ["'%s'" % (x,) for x in self.__macros] |
|---|
| 63 |
while(k < len(macros)): |
|---|
| 64 |
name, value = macros[k:k+2] |
|---|
| 65 |
self.add_define_macro((name, value)) |
|---|
| 66 |
self.add_undefine_macro(name) |
|---|
| 67 |
k += 2 |
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 |
class Weaver(object): |
|---|
| 71 |
""" |
|---|
| 72 |
Subclass from me to conveniently use a separate C code file for inline |
|---|
| 73 |
operations. |
|---|
| 74 |
|
|---|
| 75 |
The code file is for the entire module in which my sublcass resides, and |
|---|
| 76 |
must be present in that module's directory under the name C{<module>.c}. It |
|---|
| 77 |
is parsed into sections with headings as inline C comments in the following |
|---|
| 78 |
format:: |
|---|
| 79 |
|
|---|
| 80 |
// <subclass>.<method in which 'c' base class method is called> |
|---|
| 81 |
|
|---|
| 82 |
The subclass name must start with a capital letter and the method name with |
|---|
| 83 |
a lowercase letter (possibly followed by one or two underscores), as is |
|---|
| 84 |
conventional. There must not be anything else but whitespace on the comment |
|---|
| 85 |
line. |
|---|
| 86 |
""" |
|---|
| 87 |
infoObj = my_info() |
|---|
| 88 |
|
|---|
| 89 |
def _parseCode(self, text): |
|---|
| 90 |
re_delimiter = re.compile( |
|---|
| 91 |
"//\s+([A-Z][A-Za-z0-9_]+)\.(_{0,2}[a-z][A-Za-z0-9_]+)\s*$") |
|---|
| 92 |
cName = self.__class__.__name__ |
|---|
| 93 |
key = None |
|---|
| 94 |
lines = [] |
|---|
| 95 |
result = {'support':None} |
|---|
| 96 |
for line in text.split("\n"): |
|---|
| 97 |
m = re_delimiter.match(line) |
|---|
| 98 |
if m is None: |
|---|
| 99 |
if key: |
|---|
| 100 |
lines.append(line) |
|---|
| 101 |
continue |
|---|
| 102 |
if lines: |
|---|
| 103 |
result[key] = "\n".join(lines) |
|---|
| 104 |
lines = [] |
|---|
| 105 |
if m.group(1) == cName: |
|---|
| 106 |
key = m.group(2) |
|---|
| 107 |
else: |
|---|
| 108 |
key = None |
|---|
| 109 |
if lines: |
|---|
| 110 |
result[key] = "\n".join(lines) |
|---|
| 111 |
return result |
|---|
| 112 |
|
|---|
| 113 |
def _get_code(self): |
|---|
| 114 |
if not hasattr(self, '_code'): |
|---|
| 115 |
moduleName = self.__class__.__module__.split(".")[-1] |
|---|
| 116 |
self._code = self._parseCode( |
|---|
| 117 |
resource_string(__name__, "%s.c" % moduleName)) |
|---|
| 118 |
return self._code |
|---|
| 119 |
code = property(_get_code) |
|---|
| 120 |
|
|---|
| 121 |
def inline(self, *args, **kw): |
|---|
| 122 |
""" |
|---|
| 123 |
Call this method to run the inline code for the calling method of the |
|---|
| 124 |
subclass. |
|---|
| 125 |
|
|---|
| 126 |
Supply the names of variables to use as arguments in order as |
|---|
| 127 |
arguments. The variables can have their values set via keywords; |
|---|
| 128 |
otherwise they will be retrieved from the caller's namespace or, |
|---|
| 129 |
failing that, from my instance's namespace as C{self.<varname>}. |
|---|
| 130 |
|
|---|
| 131 |
A reference to the result of the inline call, set inside the C code via |
|---|
| 132 |
the variable I{return_val}, is returned. |
|---|
| 133 |
""" |
|---|
| 134 |
local_dict = kw |
|---|
| 135 |
frame = inspect.currentframe() |
|---|
| 136 |
methodName = frame.f_back.f_code.co_name |
|---|
| 137 |
callerVarNames = frame.f_back.f_locals.keys() |
|---|
| 138 |
try: |
|---|
| 139 |
for varName in args: |
|---|
| 140 |
if varName in kw: |
|---|
| 141 |
continue |
|---|
| 142 |
if varName in callerVarNames: |
|---|
| 143 |
local_dict[varName] = frame.f_back.f_locals[varName] |
|---|
| 144 |
elif hasattr(self, varName): |
|---|
| 145 |
local_dict[varName] = getattr(self, varName) |
|---|
| 146 |
else: |
|---|
| 147 |
raise AttributeError( |
|---|
| 148 |
"Variable '%s' not defined " % varName +\ |
|---|
| 149 |
"in keyword, caller, or instance namespace") |
|---|
| 150 |
finally: |
|---|
| 151 |
# Avoid cycle problems, per Python Library Reference 3.11.4 |
|---|
| 152 |
del frame |
|---|
| 153 |
return inline( |
|---|
| 154 |
self.code[methodName], args, local_dict, |
|---|
| 155 |
customize=self.infoObj, support_code=self.code['support']) |
|---|
| 156 |
|
|---|
| 157 |
def inlineDirect(self, code, **kw): |
|---|
| 158 |
""" |
|---|
| 159 |
Call this method with a string of C I{code} and keywords defining the |
|---|
| 160 |
names and values of variables to be passed to the code function. |
|---|
| 161 |
|
|---|
| 162 |
Using this method entails less CPU overhead (but also less convenience |
|---|
| 163 |
and flexibility) than using L{inline}. |
|---|
| 164 |
""" |
|---|
| 165 |
return inline( |
|---|
| 166 |
code, kw.keys(), kw, |
|---|
| 167 |
customize=self.infoObj, support_code=self.code['support']) |
|---|