Changeset 145
- Timestamp:
- 04/10/08 22:47:22 (8 months ago)
- Files:
-
- projects/AsynCluster/trunk/svpmc/model.c (modified) (1 diff)
- projects/AsynCluster/trunk/svpmc/model.py (modified) (2 diffs)
- projects/AsynCluster/trunk/svpmc/sample.c (modified) (3 diffs)
- projects/AsynCluster/trunk/svpmc/sample.py (modified) (6 diffs)
- projects/AsynCluster/trunk/svpmc/test/test_model.py (modified) (3 diffs)
- projects/AsynCluster/trunk/svpmc/test/test_sample.py (modified) (2 diffs)
- projects/AsynCluster/trunk/svpmc/test/test_weave.py (modified) (3 diffs)
- projects/AsynCluster/trunk/svpmc/weave.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
projects/AsynCluster/trunk/svpmc/model.c
r143 r145 83 83 84 84 85 // Model. simulateVolatilities85 // Model.draw_h 86 86 // 87 87 // Supplied variables 88 88 // ---------------------------------------------------------------------------- 89 // h Volatility values ( initially empty), [pn] array89 // h Volatility values (values to be overwritten), [pn] array 90 90 // v Volatility shock values, [pn] array 91 91 // d Volatility offset, [p] vector projects/AsynCluster/trunk/svpmc/model.py
r144 r145 266 266 267 267 def reverse(self, a, b): 268 return self.c( 269 'v', 'y', 'a', 'b', v=s.empty_like(self.y), a=a, b=b) 268 return self.c('v', 'y', 'a', 'b', v=s.empty_like(self.y)) 270 269 271 270 def forward(self, v, a, b): 272 return self.c( 273 'y', 'v', 'a', 'b', y=s.empty_like(v), v=v, a=a, b=b) 271 return self.c('y', 'v', 'a', 'b', y=s.empty_like(v)) 274 272 275 273 … … 340 338 341 339 342 #--- Methods -------------------------------------------------------------- 343 344 345 346 347 348 def pDistribution(self, paramSequence, N, M=1): 349 """ 350 After application of the normalization and distribution parameters from 351 the supplied parameter sequence, returns a 1d array of I{N} points over 352 the range of my normalized data and a 1d array of probability densities 353 for each. 354 355 You can compute the probability densities over a multiple of the data 356 range by setting the keyword I{M} to something greater than 1. 357 """ 358 # TODO 359 360 def likelihood(self, paramSequence): 361 """ 362 Returns the log-likelihood of my normalized data given my distribution, 363 after application of the parameters from the supplied parameter 364 sequence. 340 #--- Supporting Methods --------------------------------------------------- 341 342 def draw_h(self, wiggle): 343 """ 344 Iterates my normal walkers by one step using the supplied fraction 345 I{wiggle} and returns a 2-D array of volatilities, one row for each of 346 my time series of observations. 347 """ 348 if not hasattr(self, 'h'): 349 self.h = s.empty_like(self.nw.x) 350 self.nw.step(wiggle) 351 return self.c('h', 'v', 'd', 'e', v=self.nw.correlate(self.f)) 352 353 354 #--- The API -------------------------------------------------------------- 355 356 def likelihood(self, wiggle, paramSequence): 357 """ 358 Returns a log-likelihood of my observations for one set of simulated 359 volatilies, given the supplied fractional I{wiggle} and the parameter 360 arrays in the supplied sequence I{paramSequence}. 365 361 366 362 This method returns the likelihood of the data given the parameters. It 367 363 does not consider the prior probability of the parameters. You have to 368 do that yourself via a separate call to L{pPriors}, preferably before 369 calling this method. If the prior probability of any parameter is zero, 370 the posterior density for that parameter will also be zero, and a call 371 to this method will be unnecessary. 372 """ 373 # TODO 364 do that yourself, preferably before calling this method. If the prior 365 probability of any parameter is zero, the posterior density for that 366 parameter will also be zero, and a call to this method will be 367 unnecessary. 368 """ 369 for k, value in enumerate(paramSequence): 370 setattr(self, self.paramNames[k], value) 371 # Obtain innovations as residuals of the reversed VAR(1) 372 x = self.var.reverse(self.a, self.b) 373 # Draw a new set of simulated volatilities 374 h = self.draw_h(wiggle) 375 # Compute the conditional densities 376 projects/AsynCluster/trunk/svpmc/sample.c
r144 r145 42 42 43 43 44 // NormalWalk. __call__44 // NormalWalk.step 45 45 // 46 46 // Supplied variables 47 47 // ---------------------------------------------------------------------------- 48 // x 2-D array of random walker values49 // p 2-D array of log-probabilities for each value in x50 // m Oversampling ratio51 // w 2-D array of wiggle values forthe uniform random walk proposals48 // x 2-D array of random walker values 49 // p 2-D array of log-probabilities for each value in x 50 // m Oversampling ratio 51 // wiggle Wiggle (0-1) for scaling the uniform random walk proposals 52 52 53 53 int i, j, k; … … 61 61 for(k=0; k<m; k++) { 62 62 // Generate a uniform, symmetric, random walk proposal 63 xp = X2(i,j) + W2(i,j)* (drand48() - 0.5);63 xp = X2(i,j) + wiggle * (drand48() - 0.5); 64 64 // Do the ratio in log space 65 65 p_xp = -0.5 * pow(xp, 2); … … 83 83 // Supplied variables 84 84 // ---------------------------------------------------------------------------- 85 // y 2-D array of correlated random va lues (initially empty)86 // x 2-D array of independent random va lues87 // p2-D array of cross-correlations between values in each column of x85 // y 2-D array of correlated random variates (to be overwritten) 86 // x 2-D array of independent random variates 87 // r 2-D array of cross-correlations between values in each column of x 88 88 89 89 int i, j, k; 90 90 double sum; 91 92 // For each column ...93 for(i= 1; i<Nv[1]; i++) {94 // For each time series...95 for( i=0; i<Nv[0]; i++) {96 // The offset plus the current shock...97 sum = D1(i) + V2(i,j);98 // ...plus the dot product for the VAR(1) term...99 for(k=0; k<N v[0]; k++)100 sum += E2(i,k) * H2(k,j-1);101 // ...is the modeled output102 H2(i,j) = sum;91 92 // For each column of independent variates to be correlated... 93 for(i=0; i<Nx[1]; i++) { 94 // For each of the values in the column... 95 for(j=0; j<Nx[0]; j++) { 96 // The matrix product of the cross-correlations and the independent 97 // variates... 98 sum = 0; 99 for(k=0; k<Nx[0]; k++) 100 sum += R2(j,k) * X2(k,i); 101 // ...is the correlated output 102 Y2(j,i) = sum; 103 103 } 104 104 } projects/AsynCluster/trunk/svpmc/sample.py
r144 r145 63 63 x[:,0] = K*W[I0] 64 64 a = s.less(x[:,0], 1.0).nonzero()[0] 65 x = self.c('x', 'a', 'b', x=x, a=a,b=s.setdiff1d(s.arange(0, K), a))65 x = self.c('x', 'a', 'b', b=s.setdiff1d(s.arange(0, K), a)) 66 66 V = s.rand(N) 67 67 RI = s.random.randint(0, K, N) … … 74 74 I run a 2-D array of values through a random walk within a zero-mean, unit 75 75 variance normal distribution. 76 77 Call an instance of me with an array I{w} of fractional wiggle values in78 the range 0.0 to +1.0, with one array element for each of my random79 walkers. The elements of my value array will be perturbed accordingly and80 updated array returned.81 76 """ 82 77 m = 10 … … 85 80 self.x = s.randn(rows, cols) 86 81 self.p = s.zeros_like(self.x) 82 self.r = s.empty_like(self.x) 87 83 88 def __call__(self, w): 89 if s.shape(w) != self.x.shape: 90 raise ValueError( 91 "Wiggle array must have same dimensions as walker array") 92 return self.c('x', 'p', 'm', 'w', w=w) 84 def step(self, wiggle): 85 """ 86 Call with a fractional wiggle value in the range 0.0 to +1.0. The 87 elements of my value array will be perturbed via a random walk MCMC 88 step with a symmetric, uniform proposal over +/- half the wiggle value. 89 90 A reference to the updated array is returned. 91 """ 92 return self.c('x', 'p', 'm', 'wiggle') 93 93 94 94 def _covarMatrix(self, correlations): … … 98 98 """ 99 99 i = 0 100 p= self.x.shape[0]101 c = s.ones((p, p))102 for j in xrange( p-1):103 for k in xrange(j+1, p):104 c [j, k] = c[k, j] = correlations[i]100 n = self.x.shape[0] 101 cv = s.ones((n, n)) 102 for j in xrange(n - 1): 103 for k in xrange(j+1, n): 104 cv[j, k] = cv[k, j] = correlations[i] 105 105 i += 1 106 return c 106 return cv 107 107 108 108 def correlate(self, correlations=None): … … 112 112 which are in the following form:: 113 113 114 [r01, r02,..., r0 p, r12,..., r1p,..]114 [r01, r02,..., r0n, r12,..., r1n,..] 115 115 116 116 The values in each column of the result are correlated. The values from … … 122 122 """ 123 123 if correlations: 124 self.c = linalg.cholesky( 124 # Generate the correlation matrix and save in case not supplied 125 # next time 126 self.r = linalg.cholesky( 125 127 self._covarMatrix(correlations), lower=True) 128 self.y = s.empty_like(self.x) 129 n = self.x.shape[0] 130 if s.shape(getattr(self, 'r', None)) != (n, n): 131 raise ValueError( 132 "Must have a [%d x %d] cross-correlation matrix defined" \ 133 % (n, n)) 134 return self.c('y', 'x', 'r', y=s.empty_like(self.x)) 126 135 127 136 137 projects/AsynCluster/trunk/svpmc/test/test_model.py
r143 r145 21 21 22 22 import scipy as s 23 from scipy import random23 from scipy import stats, random 24 24 25 25 from twisted.internet import reactor, defer … … 32 32 import util 33 33 34 35 VERBOSE = True 34 36 35 37 PRICES = """ … … 168 170 169 171 def _plot(self, *vars): 170 N = len(vars) 172 if VERBOSE: 173 N = len(vars) 174 fig = self.fig 175 for k, var in enumerate(vars): 176 sp = fig.add_subplot(100*N+k+11) 177 sp.plot(var) 178 sp.grid(True) 179 180 def test_forward_indep_drift(self): 181 n = 1000 182 a = s.array([1.0, 1.0]) 183 v = s.zeros((2, n)) 184 for k in xrange(100): 185 b1, b2 = 0.8*s.rand(2) + 0.1 186 b = s.array([[b1, 0.0], [0.0, b2]]) 187 y = self.var.forward(v, a, b) 188 for k, bk in enumerate((b1, b2)): 189 self.failUnlessAlmostEqual(y[k,n/2:].mean(), 1.0/(1-bk), 3) 190 191 def test_forward_indep_shocks(self): 192 n = 10000 193 b1, b2 = 0.95, 0.8 194 a = s.array([0.0, 0.0]) 195 b = s.array([[b1, 0.0], [0.0, b2]]) 196 v = s.randn(2, n) 197 y = self.var.forward(v, a, b) 198 # IIR filtering 171 199 fig = self.fig 172 for k, var in enumerate(vars): 173 sp = fig.add_subplot(100*N+k+11) 174 sp.plot(var) 175 sp.grid(True) 176 177 def test_forward_indep(self): 178 a = s.array([1.0, 1.0]) 179 b = s.array([[0.8, 0.0], [0.0, 0.2]]) 180 v = 0.1*s.randn(2, 100) 181 y = self.var.forward(v, a, b) 182 self._plot(y[0,:], y[1,:]) 183 184 def test_reverse_indep(self): 185 a = s.array([1.0, 1.0]) 186 b = s.array([[0.8, 0.0], [0.0, 0.2]]) 187 v1 = 0.1*s.randn(2, 100) 188 _y = self.var.y 189 self.var.y = self.var.forward(v1, a, b) 190 v2 = self.var.reverse(a, b) 191 self._plot(v1[0,:], v2[0,:], v1[1,:], v2[1,:]) 192 self.var.y = _y 200 for k, bk in enumerate((b1, b2)): 201 sp = fig.add_subplot(221 + 2*k) 202 pxx = sp.psd(y[k,n/2:], NFFT=32)[0] 203 ratio = ( pxx[-1]/pxx[0] ) / ( 2*((1-bk)/(1+bk))**2 ) 204 self.failUnless(ratio > 0.4, "Too little rolloff in PSD") 205 self.failUnless(ratio < 1.5, "Too much rolloff in PSD") 206 sp = fig.add_subplot(221 + 2*k + 1) 207 sp.plot(y[k,:]) 208 # Uncorrelated 209 r = stats.spearmanr(y[0,:], y[1,:])[0] 210 self.failUnless(abs(r) < 0.1, "Doesn't appear uncorrelated") 193 211 194 212 def test_forward_xcorr(self): 213 n = 1000 195 214 a = s.array([0.0, 0.0]) 196 215 b = s.array([[0.0, 0.5], [0.0, 0.0]]) 197 v = 0.1*s.randn(2, 100)216 v = 0.1*s.randn(2, n) 198 217 y = self.var.forward(v, a, b) 199 self._plot(v[0,:], v[1,:], y[0,:]) 200 201 def test_reverse_xcorr(self): 202 a = s.array([1.0, 1.0]) 203 b = s.array([[0.01, 0.5], [0.01, 0.01]]) 204 v1 = 0.1*s.randn(2, 100) 218 # Correlation 219 nd = 6 220 d = s.arange(-nd, nd+1) 221 r = s.array( 222 [s.correlate(y[0,nd+lag:n-nd+lag], y[1,nd:n-nd])[0] for lag in d]) 223 lagOneMetric = r[nd+1] / max(s.concatenate([r[:nd+1], r[nd+1:]])) 224 self.failUnless(lagOneMetric < 10) 225 if VERBOSE: 226 sp = self.fig.add_subplot(111) 227 sp.plot(d, r, 'o-') 228 sp.grid(True) 229 230 def test_reverse(self): 231 n = 200 232 t = 2*s.pi*s.arange(n)/n 233 v1 = 0.1*s.randn(2,n) 205 234 _y = self.var.y 206 self.var.y = self.var.forward(v1, a, b) 207 v2 = self.var.reverse(a, b) 208 for k in (0,1): 209 self._plot(v1[0,:], v1[1,:], self.var.y[k,:], v2[k,:]) 235 for j in xrange(100): 236 a = s.randn(2) 237 # Keep all coefficients small enough to ensure stability 238 b = 0.6*s.rand(2,2) 239 # Forward... 240 self.var.y = self.var.forward(v1, a, b) 241 # ...then reverse 242 v2 = self.var.reverse(a, b) 243 # Now check 244 for k in (0,1): 245 diff = s.absolute(v1[k,:] - v2[k,:]) 246 if max(diff) > 1E-1: 247 table = "\n".join([ 248 ", ".join(["%6.5f" % x for x in row]) 249 for row in diff.reshape(20, n/20)]) 250 self.fail( 251 "Run #%d: excess round trip error:\n\n%s" \ 252 % (j+1, "b:\n%s\n\n|diff|:\n%s" % (str(b), table))) 210 253 self.var.y = _y 254 projects/AsynCluster/trunk/svpmc/test/test_sample.py
r144 r145 82 82 sp.hist(x, bins=20) 83 83 84 def walkTwo(self, N, p=2): 85 M = 20 86 NM = N*M 87 for k in xrange(NM): 88 x = self.walker.step(0.5) 89 if k % M == 0: 90 yield x 91 84 92 def test_univariate_bigJumps(self): 85 93 walker = sample.NormalWalk(1, 1) 86 w = s.array([[1.0]]) 87 x = s.array([walker(w)[0,0] for k in xrange(200)]) 94 x = s.array([walker.step(1.0)[0,0] for k in xrange(200)]) 88 95 self.check(x) 89 96 90 97 def test_univariate_smallJumps(self): 91 98 walker = sample.NormalWalk(1, 1) 92 w = s.array([[0.1]]) 93 x = s.array([walker(w)[0,0] for k in xrange(20000)]) 99 x = s.array([walker.step(0.1)[0,0] for k in xrange(20000)]) 94 100 self.check(x[::100]) 95 101 96 102 def test_multivariate(self): 97 N , T = 10, 2000098 walker = sample.NormalWalk(N, 2)99 w = s.column_stack([0.5*s.ones(N), 0.3*s.ones(N)])100 x1 = s.empty(T)101 x2 = s.empty(T)102 for k in xrange(T):103 x = walker(w)104 x1[k] = x[1,0]105 x2[k] = x[8,1]106 self. check(x1[::100])107 self.check(x2[::100])108 self.fig.add_subplot(111).plot(x1, x2)103 N = 100 104 x1 = s.empty(N) 105 x2 = s.empty(N) 106 self.walker = sample.NormalWalk(2, 2) 107 for k, x in enumerate(self.walkTwo(N)): 108 x1[k] = x[0,0] 109 x2[k] = x[1,1] 110 self.check(x1) 111 self.check(x2) 112 self.failUnless(stats.pearsonr(x1, x2)[1] > 0.05) 113 if VERBOSE: 114 self.fig.add_subplot(111).plot(x1, x2) 109 115 110 116 def test_covarMatrix_2x2(self): … … 132 138 [0.14, 0.24, 0.34, 1.00]]) 133 139 self.failUnless(s.equal(x, y).all()) 140 141 def test_correlate(self): 142 def vector(row, col): 143 return s.array([x[row, col] for x in yList]) 144 145 N = 500 146 yList = [] 147 self.walker = sample.NormalWalk(2, 2) 148 self.failUnlessEqual(self.walker.correlate([0.5]).shape, (2,2)) 149 for k, x in enumerate(self.walkTwo(N)): 150 y = self.walker.correlate() 151 yList.append(y.copy()) 152 # Correlated values in columns 153 for col in (0,1): 154 y1 = vector(0,col) 155 y2 = vector(1,col) 156 self.check(y1) 157 self.check(y2) 158 corrInfo = stats.pearsonr(y1, y2) 159 self.failUnless( 160 abs(corrInfo[0] - 0.5) < 0.1, 161 "Expected correlation of 0.5, not %f" % corrInfo[0]) 162 if VERBOSE: 163 self.fig.add_subplot(111).plot(y1, y2) 164 # Uncorrelated values in rows 165 for row in (0,1): 166 y1 = vector(row,0) 167 y2 = vector(row,1) 168 self.check(y1) 169 self.check(y2) 170 corrInfo = stats.pearsonr(y1, y2) 171 self.failUnless( 172 abs(corrInfo[0]) < 0.1, 173 "Expected correlation of 0, not %f" % corrInfo[0]) 174 if VERBOSE: 175 self.fig.add_subplot(111).plot(y1, y2) projects/AsynCluster/trunk/svpmc/test/test_weave.py
r140 r145 56 56 57 57 def __call__(self, x): 58 return self.c('x' , x=s.array([x]))[0]58 return self.c('x')[0] 59 59 60 60 def foo(self, x): … … 68 68 def test_c_alone(self): 69 69 self.weaver._code = {'support':None, 'foo':CODE} 70 self.failUnlessEqual(self.weaver.foo( 1), 1164)70 self.failUnlessEqual(self.weaver.foo(s.array([1])), 1164) 71 71 72 72 def test_parseCode(self): … … 80 80 def test_c_privateMethod(self): 81 81 self.weaver._code = self.weaver._parseCode(CODE) 82 self.failUnlessEqual(self.weaver( 7), 107)82 self.failUnlessEqual(self.weaver(s.array([7])), 107) projects/AsynCluster/trunk/svpmc/weave.py
r140 r145 17 17 18 18 """ 19 Miscellaneous utility stuff 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. 20 23 """ 21 24 … … 80 83 Supply the names of variables to use as arguments in order as 81 84 arguments. The variables can have their values set via keywords; 82 otherwise they will be retrieved as instance attributes. 85 otherwise they will be retrieved from the caller's namespace or, 86 failing that, from my instance's namespace as C{self.<varname>}. 83 87 84 88 A reference to the first variable is returned. 85 89 """ 86 for varName in args: 87 value = kw.get(varName, getattr(self, varName, None)) 88 exec "%s = value" % varName 89 methodName = inspect.currentframe().f_back.f_code.co_name 90 frame = inspect.currentframe() 91 methodName = frame.f_back.f_code.co_name 92 callerVarNames = frame.f_back.f_locals.keys() 93 try: 94 for varName in args: 95 if varName in kw: 96 value = kw[varName] 97 elif varName in callerVarNames: 98 value = frame.f_back.f_locals[varName] 99 elif hasattr(self, varName): 100 value = getattr(self, varName) 101 else: 102 raise AttributeError( 103 "Variable '%s' not defined " % varName +\ 104 "in keyword, caller, or instance namespace") 105 exec "%s = value" % varName 106 finally: 107 # Avoid cycle problems, per Python Library Reference 3.11.4 108 del frame 90 109 inline( 91 110 self.code[methodName],
