Changeset 177

Show
Ignore:
Timestamp:
05/10/08 22:37:06 (7 months ago)
Author:
edsuom
Message:

Working on new truncated-normal zProposal

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • projects/AsynCluster/trunk/svpmc/model.c

    r158 r177  
    8383 
    8484 
     85// Model.support 
     86// ---------------------------------------------------------------------------- 
     87 
     88// Normal (zero mean, unit variance) probability density 
     89double npdf(double x) 
     90{ 
     91  // 1/sqrt(2*pi) = 0.39894228... 
     92  return 0.398942280401 * exp(-0.5 * pow(x, 2)); 
     93} 
     94 
     95 
     96// Normal (zero mean, unit variance) cumulative density 
     97double ncdf(double x) 
     98{ 
     99  double ax, t, sum; 
     100  // The cdf is computed from the absolute value of x and corrected at the end 
     101  // if necessary 
     102  ax = fabs(x); 
     103  // Compute t, the variable used in the series summation 
     104  t = 1.0 / (1.0 + 0.2316419*ax); 
     105  // Efficiently compute the series summation 
     106  sum  =  t       * +0.31938;   // t 
     107  sum += (t *= t) * -0.35656;   // t^2 
     108  sum += (t *= t) * +1.78148;   // t^3 
     109  sum += (t *= t) * -1.82125;   // t^4 
     110  sum += (t *= t) * +1.33027;   // t^5 
     111  // Compute the cdf, assuming x to be positive 
     112  sum *= (1.0 - npdf(ax)); 
     113  // Correct if x < 0 
     114  if(x < 0) 
     115    sum = 1 - sum; 
     116  // All done 
     117  return sum; 
     118} 
     119 
     120 
     121// Truncated normal (zero mean, unit variance) probability density 
     122double tnpdf(double x, double a, double b) 
     123{ 
     124  double y; 
     125  if(x < a || x > b) { 
     126    y = 0; 
     127  } else { 
     128    y = npdf(x) / (ncdf(b) - ncdf(a)); 
     129  } 
     130  return y; 
     131} 
     132  
     133 
     134 
    85135// Model.zProposal 
    86136// 
     
    88138// ---------------------------------------------------------------------------- 
    89139// z    Independent normal variates, [pn] array (updated) 
    90 // M    Number of uniform-proposal MCMC iterations per IID normal draw 
    91 // wiggle = Width of random-walk uniform proposal 
    92  
    93  
    94 int k0, k1, k2
    95 double norm, normp, L, Lp, dL; 
     140// wiggle = half-width of independent uniform proposal 
     141 
     142#define  w  (double)wiggle 
     143 
     144int k0, k1
     145double x, zk, c, cp, L; 
    96146 
    97147// Seed the PRNG on the first run only 
     
    111161} 
    112162 
     163// The joint log-density of all the jumps 
     164L = 0; 
    113165// for each multivariate sample... 
    114166for(k0=0; k0<Nz[1]; k0++) { 
    115167 
    116   // Do a random walk from this column of independent random-walk normal 
    117   // variates to produce a multivariate iid normal proposal. It is this on 
    118   // which we build a multivariate log-volatility proposal for this 
    119   // multivariate sample. 
     168  // Do a random walk (a single uniformly distributed step) from this column of 
     169  // independent random-walk normal variates to produce a multivariate iid 
     170  // normal proposal. It is this on which we build a multivariate 
     171  // log-volatility proposal for this multivariate sample. 
    120172   
    121173  // For each time series... 
    122174  for(k1=0; k1<Nz[0]; k1++) { 
    123     // Initialize the current normal value with the current proposal value and 
    124     // compute its log-likelihood 
    125     norm = Z2(k1, k0); 
    126     L = -0.5 * pow(norm, 2); 
    127     // For each oversampling iteration... 
    128     for(k2=0; k2<M; k2++) { 
    129       // Generate a uniform, symmetric, random walk proposal 
    130       normp = norm + (double) wiggle * (drand48() - 0.5); 
    131       // Do the ratio in log space 
    132       Lp = -0.5 * pow(normp, 2); 
    133       dL = Lp - L; 
    134       // The uniform random variate thus needs to be in logspace as well, but 
    135       // it's not always even needed. Thus the log operation is done just 
    136       // once, and only some of the time. 
    137       if(dL > 0  || log(drand48()) < dL) { 
    138         // Update current value and its log probability when proposal 
    139         // accepted 
    140         norm = normp; 
    141         L = Lp; 
    142       } 
     175    // Compute the scale value c as a bit more* than the maximum pdf (regular 
     176    // normal distribution) at the endpoints and middle of the truncated range 
     177    c = 0; 
     178    zk = Z2(k1, k0); 
     179    for(x = -w; x < w; x += w) { 
     180      cp = 1.12 * npdf(zk + x); // *Scaling by 1.12 works for w <= 1.0 
     181      if(cp > c) 
     182        c = cp; 
    143183    } 
    144     // Update this element of the IID normal array in place 
    145     Z2(k1, k0) = norm; 
    146   } 
    147 
     184    // Accept-reject sampling for the truncated normal distribution 
     185    do { 
     186      // Generate a proposal within the truncated range 
     187      x = zk + 2*w*(drand48() - 0.5); 
     188      // Compute the pdf of the proposal, using the regular normal distribution 
     189      cp = npdf(x); 
     190      // Accept (and exit the loop) when the scaled uniform variate is less 
     191      // than the proposal's pdf 
     192    } while(c*drand48() > cp); 
     193    // Update this element of the IID normal array in place with the accepted 
     194    // proposal 
     195    Z2(k1, k0) = x; 
     196    // Add the log-density of the accepted proposal 
     197    L += log(tnpdf(x, zk-w, zk+w)); 
     198  } 
     199
     200 
     201return_val = L; 
    148202 
    149203 
  • projects/AsynCluster/trunk/svpmc/model.py

    r176 r177  
    2121 
    2222import scipy as s 
    23 from scipy import linalg 
     23from scipy import linalg, stats 
    2424 
    2525from twisted.internet import defer 
     
    257257        return logU[self._logU_index] 
    258258 
    259     def zProposal(self, z, sigma): 
    260         """ 
    261         Does a random walk from the supplied 2-D array I{z} of normal random 
    262         variates, using a symmetric normal proposal distribution with standard 
    263         deviation I{sigma}. 
     259    def zProposal(self, z, wiggle): 
     260        """ 
     261        Does a random walk step from the supplied 2-D array I{z} of zero-mean, 
     262        unit-variance normal random variates with a jump from a uniform 
     263        distribution having width +/- I{wiggle}. 
     264         
     265        Returns a copy of the array with all elements changed from the original 
     266        values, independently, along with the total log-density of the jumps. 
    264267        """ 
    265268        z = z.copy() 
    266         self.inline('z', 'M', 'wiggle', M=self.Mz, wiggle=sigma
    267         return z 
     269        L = self.inline('z', 'M', 'wiggle', M=self.Mz
     270        return z, L 
    268271     
    269272    def logVolatilities(self, z, v, x, h0): 
     
    322325        """ 
    323326        L_total = 0 
    324         L_result = 0 
    325327        acceptances = 0 
    326328        N = self.decaySamples(tol) 
     
    332334        # ...and a set of random-walk proposals for the IID variates, along 
    333335        # with their volatility shocks 
    334         zp = self.zProposal(z, sigma) 
     336        zp, L_result = self.zProposal(z, sigma) 
    335337        vp = s.array(rv*zp) 
    336338        # Do conditional draws of each sample in turn 
     
    412414            3. The IID normal variates underlying the log-volatilities. 
    413415 
    414             4. The log-probability of the simulated result. 
     416            4. The log-probability of the simulated result, normalized to be 
     417               independent of the number of hybrid Gibbs steps. 
    415418 
    416419            5. The mean acceptance rate of the Metropolis-Hastings proposals. 
     
    447450        except linalg.LinAlgError: 
    448451            return 
    449         return info[0], info[1], z, L_result, sum(acceptRates)/self.Mv 
    450      
     452        return info[0], info[1], z, L_result/self.Mv, sum(acceptRates)/self.Mv 
     453     
  • projects/AsynCluster/trunk/svpmc/test/test_model.py

    r175 r177  
    331331        self.failUnless(percent < 40) 
    332332 
    333     def test_zProposal(self): 
     333    def test_zProposal_dist(self): 
    334334        N = 1000 
    335335        z = s.zeros((2,3)) 
     
    338338        z2 = s.empty(N) 
    339339        for k in xrange(N): 
    340             z = modelObj.zProposal(z, 0.5
     340            z, L_result = modelObj.zProposal(z, 0.8
    341341            z1[k] = z[0,0] 
    342342            z2[k] = z[1,1] 
    343         self.failUnlessNormal(z1[0.7*N:]
    344         self.failUnlessNormal(z2[0.7*N:]
     343        self.failUnlessNormal(z1
     344        self.failUnlessNormal(z2
    345345        self._check_uncorr(z1, z2) 
    346346 
     347    def test_zProposal_L(self): 
     348        N = 1000 
     349        z0 = s.ones((1,1)) 
     350        modelObj = self.modelFactory() 
     351        z = s.empty(N) 
     352        L = s.empty(N) 
     353        for k in xrange(N): 
     354            zk, L_result = modelObj.zProposal(z0, 0.8) 
     355            z[k] = zk[0,0] 
     356            L[k] = L_result 
     357        fig = self.fig 
     358        sp = fig.add_subplot(211) 
     359        sp.hist(z) 
     360        sp = fig.add_subplot(212) 
     361        sp.plot(z, s.exp(L), '.') 
     362     
    347363    def test_decaySamples(self): 
    348364        x = s.zeros((5, 1000)) 
  • projects/AsynCluster/trunk/svpmc/test/util.py

    r168 r177  
    268268        self.failUnlessAlmostEqual(error, 0.0, places) 
    269269 
    270     def failUnlessNormal(self, x): 
     270    def failUnlessNormal(self, x, sdev=None): 
    271271        p = stats.normaltest(x)[1] 
    272272        if Mock.verbose(): 
     
    278278        self.failUnless( 
    279279            p > 0.05, "Deviation from normality with significance p=%f" % p) 
     280        if sdev: 
     281            if Mock.verbose(): 
     282                print "sdev = %f, expected %f" % (x.std(), sdev) 
     283            df = len(x) - 1 
     284            chi2 = df * x.var() / sdev**2 
     285            p = stats.chisqprob(chi2, df) 
     286            self.failUnless( 
     287                p > 0.05, 
     288                "Variance greater than expected with significance p=%f" % p) 
    280289 
    281290    @defer.deferredGenerator