Changeset 183
- Timestamp:
- 05/16/08 16:40:27 (7 months ago)
- Files:
-
- projects/AsynCluster/trunk/svpmc/model.c (modified) (14 diffs)
- projects/AsynCluster/trunk/svpmc/test/test_model.py (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
projects/AsynCluster/trunk/svpmc/model.c
r182 r183 107 107 struct sample 108 108 { 109 // Log-density of the proposal on z 110 double Lz; 111 // Log-likelihood of the current innovation, given h 112 double Lx; 113 // Linear probability density of the proposal, given h 114 double pProb; 115 // Multivariate normal proposal 109 // Log-likelihood of the innovations up to the current one, given the history 110 // of h to this point 111 double Lx = 0; 112 // Multivariate normal proposal, which is just z for time-series samples 113 // after the first in each log-volatility computation 116 114 double *z; 117 115 // Multivariate log-volatility value based on the current proposal, or the … … 124 122 125 123 126 // Uniformly distributed random variate in (a,b) 124 // A selection of a proposal sample 125 struct selection 126 { 127 int kp; 128 double Lp; 129 } 130 131 132 // Uniformly distributed random variate in [a,b) 127 133 double uniform(double a, double b) 128 134 { … … 202 208 double *y; 203 209 double val; 204 double L = 0; 205 const int N = (int) P->d->dimensions[0]; 206 210 const int N = (int) P->g->dimensions[0]; 211 207 212 // Inverse-scale the innovation by the square root of the volatilities in 208 213 // preparation for decorrelation … … 213 218 // log-likelihood computation for this multivariate log-volatility proposal 214 219 matrixMultiply(P->ri, S->x0, S->x1); 215 220 216 221 // Now compute log Pr(x[t]|h[t]), the log-likelihood of the decorrelated 217 222 // multivariate innovation for this sample, conditional on the sample's … … 230 235 // scaling coefficient 231 236 val = SPA1(S, x0, k) / SPP2(P, sc, k, 0); 232 L -= 0.5 * val*val + SPP2(P, sc, k, 1); // Fast squaring instead of pow() 237 // Fast squaring instead of pow() 238 S->Lx -= 0.5 * val*val + SPP2(P, sc, k, 1); 233 239 // Since the innovation has been inverse-scaled by the square root of the 234 240 // proposed volatility, the probability density needs to be scaled as 235 241 // well. In log space, this is a subtraction of half the log-volatility. 236 L -= 0.5 * SPA1(S, h, k); 237 } 238 239 // All done 240 S->Lx = L; 242 S->Lx -= 0.5 * SPA1(S, h, k); 243 } 241 244 } 242 245 … … 244 247 // Returns with zero only if the post-first proposals are close enough to 245 248 // finish likelihood computation 246 int notCloseEnough(struct sample *sp[ 2][], int n)249 int notCloseEnough(struct sample *sp[][2], int n) 247 250 { 248 251 int k; … … 251 254 double Lmax = -1E20; // Anything will be more positive 252 255 for(k=0; k<n; k++) { 253 L = sp[ 1][k]->Lx;256 L = sp[k][1]->Lx; 254 257 if(L < Lmin) 255 258 Lmin = L; … … 258 261 } 259 262 return (Lmax - Lmin > 0.001); 263 } 264 265 266 // Importance-samples one of the proposals based on a weight computed from the 267 // log-density of z and the log-likelihood of the innovation given the 268 // proposal's log-volatility. 269 // 270 // Returns a struct with an integer index to the sampled proposal's struct and 271 // the log-probability of the proposal's having been selected. 272 struct selection \ 273 sample(struct sample *sp[][2], double Lz[], double Dp[], int n) 274 { 275 int k0, kpMax; 276 double val; 277 double pSum = 0; 278 double pMax = -1E20; // Anything will be more positive 279 struct selection result; 280 281 // Compute linear probability density for each proposal 282 for(k0=0; k0<n; k0++) { 283 val = exp(sp[k0][1]->Lx + Lz[k0]); 284 Dp[k0] = val; 285 pSum += val; 286 if(val > pMax) { 287 pMax = val; 288 kpMax = k0; 289 } 290 291 // Accept-reject sampling with uniform random proposal selection 292 do { 293 // Randomly select one of the proposals... 294 result.kp = (int) uniform(0, n); 295 // ...until the selected proposal is accepted, with probability 296 // proportional to its relative weight 297 } while(result.kp != kpMax && uniform(0, pMax) > Dp[result.kp]); 298 299 // Only one division operation is needed! 300 result.Lp = log(Dp[result.kp] / (pMax*pSum)); 301 return result; 260 302 } 261 303 … … 288 330 // 1 Lh: Log-likelihood of simulated log-volatilities 289 331 332 333 // The number of time series making up a single multivariate sample 290 334 const int Nt = Nz[0]; 335 // The number of multivariate samples 291 336 const int Ns = Nz[1]; 292 337 293 338 int notFirst; 294 339 int k0, k1, k2, k3, kp; 295 double zp; 340 double val; 341 double Lx = 0; 296 342 double Lp = 0; 297 343 344 // Multivariate innovation for one current time-series sample 298 345 double *xk; 299 struct sample sp[2][n]; 346 // Log probability density of each proposal on z 347 double Lz[n]; 348 // Linear probability density of each log-volatility proposal 349 double Dp[n]; 350 351 // A struct for the result of the importance-sampling function 352 struct selection spSelection; 353 // Two sets of proposal sample structs, one for the first time-series sample in 354 // each log-volatility computation (from which the innovation's log-volatility 355 // is computed) and another for all time-series samples thereafter. 356 struct sample sp[n][2]; 357 // A struct for the model parameters 300 358 struct parameters P; 359 360 // The results go here 301 361 py::tuple result(2); 302 362 … … 309 369 xk = (double *) calloc(sizeof(double), Nt); 310 370 for(k0=0; k0<n; k0++) { 311 for(k1=0; k1< n; k1++) {371 for(k1=0; k1<2; k1++) { 312 372 sp[k0][k1].h = (double *) calloc(sizeof(double), Nt); 313 373 sp[k0][k1].x0 = (double *) calloc(sizeof(double), Nt); … … 316 376 } 317 377 318 // For each sample...378 // For each time-series sample... 319 379 for(k0=0; k0<Ns; k0++) { 320 380 … … 323 383 324 384 k1 = k0; 385 notFirst = 0; 386 for(k2=0; k2<n; k2++) 387 Lz[k2] = 0; 388 325 389 do { 326 390 327 // Prepare current-innovation vector xk and a set of sample structs for 328 // proposals, one set for the first time-series sample and another set for 329 // any remaining time-series samples to be computed 391 // Prepare current-innovation vector xk 330 392 for(k2=0; k2<Nt; k2++) 331 393 PA1(xk, k2) = X2(k2, k1); 332 if(k1 == k0) { 333 // First time-series sample 334 notFirst = 0; 335 } else if(k1 == k0+1) { 336 // Second time-series sample, copy h arrays from proposal structs for 337 // first time-series sample 338 notFirst = 1; 339 for(k2=0; k2<n; k2++) { 340 for(k3=0; k3<Nt; k3++) 341 SPA1(sp[1][k2], h, k3) = SPA1(sp[0][k2], h, k3); 342 } 343 } else { 344 // Third or later time-series sample 345 notFirst = 1; 346 } 347 348 // Make proposals on z in the set of sample structs... 394 395 // Set z for the set of sample structs... 349 396 for(k2=0; k2<n; k2++) { 350 397 for(k3=0; k3<Nt; k3++) { 351 zp = Z2(k3, k1) + uniform(-w, +w); 352 SPA1(sp[notFirst][k2], z, k3) = zp; 353 sp[notFirst][k2].Lz = normLogDensity(zp); 398 val = Z2(k3, k1); 399 if(!notFirst) { 400 // First time-series sample, use a proposal on z instead of z itself 401 val += uniform(-w, +w); 402 Lz[k2] += normLogDensity(val); 403 } 404 SPA1(sp[k2][notFirst], z, k3) = val; 354 405 } 355 406 } 356 407 // ...compute their log-volatilities 357 408 for(k2=0; k2<n; k2++) 358 logVol(&sp[ notFirst][k2], &P);409 logVol(&sp[k2][notFirst], &P); 359 410 // ...and the log-likelihood of the innovation for this time-series sample, 360 411 // for each proposal on z and its log-volatility 361 412 for(k2=0; k2<n; k2++) 362 logLikelihood(&sp[ notFirst][k2], &P, xk);413 logLikelihood(&sp[k2][notFirst], &P, xk); 363 414 364 415 // Ready for the next time series sample, if we go that far 365 416 k1++; 366 417 418 if(k1 == k0+1) { 419 // Next will be the second time-series sample... 420 notFirst = 1; 421 // ...and will be starting with copy of h arrays from proposal structs 422 // for the just-completed first time-series sample 423 for(k2=0; k2<n; k2++) { 424 for(k3=0; k3<Nt; k3++) 425 SPA1(sp[k2][1], h, k3) = SPA1(sp[k2][0], h, k3); 426 } 427 } 428 367 429 } while (k1==k0+1 || (k1<Ns && notCloseEnough(sp, n))); 368 430 369 431 // Importance sample proposal using pProb=exp(Lz+Lx) for each 370 kp = sample(sp, n); 371 Lp += log(sp[1][kp]->pProb); 372 432 spSelection = sample(sp, Lz, Dp, n); 433 Lp += log(spSelection.Lp); 434 for(k1=0; k1<Nt; k1++) 435 Z2(k1,k0) = SPA1(sp[spSelection.kp][1], z, k1); 436 437 // Set the initial log-volatility of the proposals for the next time-series 438 // sample to the log-volatility of the selected proposal for this time-series 439 // sample. 440 for(k1=0; k1<n; k1++) { 441 val = SPA1(sp[spSelection.kp][1], h, k1); 442 for(k2=0; k2<Nt; k2++) 443 SPA1(sp[k1][0], h, k2) = val; 444 } 445 446 // Done with log-volatility draw for this time-series sample 373 447 } 374 448 … … 376 450 // sample 377 451 for(k0=0; k0<Nt; k0++) 378 H1(k0) = SPA1(sp[ 1]452 H1(k0) = SPA1(sp[kp][1], h, k0); 379 453 380 454 // Free array memory 381 455 free(x0); 382 for(k0=0; k0< 2; k0++) {383 for(k1=0; k1< n; k1++) {456 for(k0=0; k0<n; k0++) { 457 for(k1=0; k1<2; k1++) { 384 458 free(sp[k0][k1].h); 385 459 free(sp[k0][k1].x0); … … 391 465 result[0] = 0; 392 466 for(k0=0; k0<Nt; k0++) { 393 result[0] += sp[ 0][k0]->Lx;467 result[0] += sp[k0][0]->Lx; 394 468 result[1] = Lp; 395 469 return_val = result; projects/AsynCluster/trunk/svpmc/test/test_model.py
r181 r183 358 358 359 359 code = """ 360 int k ;360 int k0, k1; 361 361 struct sample S; 362 362 struct parameters P; … … 367 367 S.x0 = (double *) malloc(sizeof(double) * Nz[0]); 368 368 S.x1 = (double *) malloc(sizeof(double) * Nz[0]); 369 for(k=0; k<Nz[0]; k++) 370 PA1(S.z, k) = Z1(k); 371 372 logVol(&S, &P); 373 374 for(k=0; k<Nz[0]; k++) 375 H1(k) = PA1(S.h, k); 369 370 for(k0=0; k0<Nz[1]; k0++) { 371 for(k1=0; k1<Nz[0]; k1++) 372 PA1(S.z, k1) = Z2(k1, k0); 373 // This is what's being tested 374 logVol(&S, &P); 375 for(k1=0; k1<Nz[0]; k1++) 376 H2(k1, k0) = PA1(S.h, k1); 377 } 376 378 """ 377 379 378 def _draw_h(self, z, d, e, fs, fr): 380 def _draw_h(self, d, e, fs, fr, z=None): 381 if z is None: 382 z = s.randn(len(d), self.N) 379 383 h = s.zeros_like(z) 380 384 rz = s.array(self._rv(fs, fr)) 381 for k, zk in enumerate(z.transpose()): 382 self.inline( 383 self.code, z=zk, 384 d=s.array(d), e=s.array(e), h=h[:,k], rz=rz) 385 self.inline( 386 self.code, z=z, d=s.array(d), e=s.array(e), h=h, rz=rz) 385 387 return h 386 388 387 389 def test_univariate_LPF(self): 388 390 e = 0.95 389 391 # Univariate model 390 z = s.randn(1, self.N) 391 h = self._draw_h(z, d=[1], e=[[e]], fs=[1], fr=[]) 392 h = self._draw_h([1], [[e]], [1], []) 392 393 # IIR filtering 393 394 self._check_psd(h, e) 394 395 395 396 def test_indep_offset(self): 396 modelObj = self.modelFactory( 397 d = s.array([1.0, 1.0]), 398 fs = [1.0, 1.0], 399 fr = [0.0]) 397 d = s.array([1.0, 1.0]) 398 fs = [1.0, 1.0] 399 fr = [0.0] 400 400 for j in xrange(10): 401 401 e1, e2 = 0.8*s.rand(2) + 0.1 402 modelObj.e = s.array([[e1, 0.0], [0.0, e2]])402 e = s.array([[e1, 0.0], [0.0, e2]]) 403 403 for k in xrange(20): 404 h = self._draw_h( modelObj)404 h = self._draw_h(d, e, fs, fr) 405 405 for m, em in enumerate((e1, e2)): 406 406 ratio = h[m,self.N/2:].mean() / ( 1.0/(1-em) ) 407 407 self.failUnlessAlmostEqual(ratio, 1.0, 0) 408 408 409 409 def test_indep_shocks(self): 410 410 e1, e2 = 0.95, 0.8 411 modelObj = self.modelFactory( 412 d = s.array([0.0, 0.0]), 413 e = s.array([[e1, 0.0], [0.0, e2]]), 414 fs = [1.0, 1.0], 415 fr = [0.0]) 416 h = self._draw_h(modelObj) 411 d = s.array([0.0, 0.0]) 412 e = s.array([[e1, 0.0], [0.0, e2]]) 413 fs = [1.0, 1.0] 414 fr = [0.0] 415 h = self._draw_h(d, e, fs, fr) 417 416 # Uncorrelated 418 417 self._check_uncorr(h[0,:], h[1,:]) … … 420 419 self._check_psd(h, e1, e2) 421 420 422 def _check_xcorr(self, dPeak, **kw): 423 modelObj = self.modelFactory(**kw) 424 h = self._draw_h(modelObj) 421 def _check_xcorr(self, dPeak, *args): 422 h = self._draw_h(*args) 425 423 # Correlation 426 424 nd = 6 … … 440 438 self._check_xcorr( 441 439 1, 442 d =[0.0, 0.0],443 e =[[0.0, 0.9], [0.0, 0.0]],444 fs =[1.0, 1.0],445 fr =[0.0],440 [0.0, 0.0], 441 [[0.0, 0.9], [0.0, 0.0]], 442 [1.0, 1.0], 443 [0.0], 446 444 ) 447 445 … … 449 447 self._check_xcorr( 450 448 0, 451 d =[0.0, 0.0],452 e =[[0.0, 0.0], [0.0, 0.0]],453 fs =[1.0, 1.0],454 fr =[0.5],449 [0.0, 0.0], 450 [[0.0, 0.0], [0.0, 0.0]], 451 [1.0, 1.0], 452 [0.5], 455 453 ) 456 454 457 455 458 class Test_Model_logVolatilities_decorrelate(BaseCase): 459 N = 1000 460 y = s.randn(1, N) 461 462 def setUp(self): 463 self.model = self.modelFactory() 464 465 def _pGenerator(self, low, high): 466 for p in xrange(low, high): 467 # Tweak the model object to make it testable for this p value 468 self.model.y = s.zeros((p, self.N)) 469 self.model.d = s.zeros(p) 470 self.model.e = s.zeros((p, p)) 471 self.model.g = s.zeros(p) 472 # Generate some bogus arrays 473 z = s.zeros((p, 1)) 474 v = s.zeros((p, 1)) 475 h0 = s.zeros((p, 1)) 476 # Yield a container with p and room for one or more 2-tuples 477 # containing a correlation parameter and arrays of innovations to 478 # decorrelate and test using that parameter value 479 container = [p] 480 yield container 481 # Use the logVolatilities method to decorrelate the innovations 482 # that the caller put into the container I just yielded 483 for self.model.cr, x in container[1:]: 484 xd = s.zeros_like(x) 485 for k in xrange(x.shape[1]): 486 self.model.logVolatilities(z, v, x[:,k], h0) 487 y = self.model.cache['lv_work'][0] 488 xd[:,k] = y[:,3] 489 # Check for non-correlation 490 for j in xrange(p): 491 for k in xrange(p): 492 if j == k: 493 continue 494 self._check_uncorr(xd[j,:], xd[k,:], plot=False) 495 496 def test_basic(self): 497 for pc in self._pGenerator(2, 4): 498 p = pc[0] 499 for correlation in s.linspace(0.1, 0.9, 5): 500 # Generate some multivariate normal test data 501 r = s.maximum(s.identity(p), correlation*s.ones((p,p))) 502 if VERBOSE: 503 print "\n\n", p 504 print r 505 c = correlation * s.ones(sum([p-k-1 for k in xrange(p)])) 506 x = random.multivariate_normal( 507 s.zeros(p), r, self.N).transpose() 508 pc.append((c, x)) 509 510 def test_complex(self): 511 for pc in self._pGenerator(2, 7): 512 p = pc[0] 513 # Stuff specific to this number of time series 514 N_correlations = sum([p-k-1 for k in xrange(p)]) 515 cMax = 0.90 / s.sqrt(p/1.5) 516 for i in xrange(10): 517 # Randomly generate a set of cross-correlations and set the 518 # model's innovation shock correlations parameter 519 c = 0.05 + cMax * s.rand(N_correlations) 520 # Generate some multivariate normal test data having the 521 # generated correlations 522 r = self._covarMatrix(s.ones(p), c) 523 if VERBOSE: 524 print "\n\n", p 525 print r 526 x = random.multivariate_normal( 527 s.zeros(p), r, self.N).transpose() 528 pc.append((c, x)) 529 530 531 class Test_Model_logVolatilities(BaseCase): 456 class Test_Model_logLikelihood(BaseCase): 532 457 N = 100 533 534 def setUp(self): 535 self.model = self.modelFactory() 458 459 code = """ 460 int k0, k1; 461 struct sample S; 462 struct parameters P; 463 464 P.g = g_array; P.ri = ri_array; P.sc = sc_array; 465 S.z = (double *) malloc(sizeof(double) * Nz[0]); 466 S.h = (double *) calloc(sizeof(double), Nz[0]); 467 S.x0 = (double *) malloc(sizeof(double) * Nz[0]); 468 S.x1 = (double *) malloc(sizeof(double) * Nz[0]); 469 470 for(k0=0; k0<Nz[1]; k0++) { 471 for(k1=0; k1<Nz[0]; k1++) 472 PA1(S.z, k1) = Z2(k1, k0); 473 // This is what's being tested 474 logLikelihood(&S, &P, x); 475 for(k1=0; k1<Nz[0]; k1++) 476 H2(k1, k0) = PA1(S.h, k1); 477 } 478 """ 479 480 def _draw_h(self, d, e, fs, fr, z=None): 481 if z is None: 482 z = s.randn(len(d), self.N) 483 h = s.zeros_like(z) 484 rz = s.array(self._rv(fs, fr)) 485 self.inline( 486 self.code, z=z, d=s.array(d), e=s.array(e), h=h, rz=rz) 487 return h 536 488 537 489 def _check_L(self, distObj, hValue):
