Changeset 202

Show
Ignore:
Timestamp:
05/28/08 23:43:21 (7 months ago)
Author:
edsuom
Message:

Using normal proposal on z instead of uniform; same result at convergence, but seems to have less Lx variance

Files:

Legend:

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

    r201 r202  
    175175 
    176176 
     177// Random variate from a truncated normal distribution 
     178double truncnorm(double a, double b) 
     179{ 
     180  int k; 
     181  register double x; 
     182  double c, cp; 
     183  const double diff = b-a; 
     184  // Compute the scale value c as the maximum possible pdf (regular normal 
     185  // distribution) within the truncated range 
     186  if(a < 0) { 
     187    if(b > 0) { 
     188      // Center is within the range, so use its pdf 
     189      c = 1; 
     190    } else { 
     191      // Range is below center, so use pdf at its right edge 
     192      c = EXP(-0.5*b*b); 
     193    } 
     194  } else { 
     195    // Range is above center, so use pdf at its left edge 
     196    c = EXP(-0.5*a*a); 
     197  } 
     198  // Accept-reject sampling for the truncated normal distribution 
     199  do { 
     200    // Generate a proposal within the truncated range 
     201    x = a + diff*drand48(); 
     202    // Compute the pdf of the proposal, using the regular normal distribution 
     203    cp = EXP(-0.5*x*x); 
     204    // Accept (and exit the loop) when the scaled uniform variate is less than 
     205    // the proposal's pdf 
     206  } while(c*drand48() > cp); 
     207  return x; 
     208} 
     209 
     210 
    177211// Matrix multiplication x*y -> z, where the square matrix 'x' is a 
    178212// PyArrayObject and 'y' and 'z' are 1-D arrays. 
     
    234268    //SPA1(S, x0, k) = exp(-0.5 * SPA1(S, h, k)) * PA1(x, k); 
    235269    // 
    236     // This is very fast, but has error of about +/-2% 
     270    // This is very fast, but has error of about +/-2%. However, the error 
     271    // doesn't seem to make any difference in the variance of log-likelihood 
     272    // estimates. 
    237273    SPA1(S, x0, k) = EXP(-0.5 * SPA1(S, h, k)) * PA1(x, k); 
    238274 
     
    310346int ki, ke; 
    311347int k0, k1, k2, k3; 
    312 double val
     348double val, maxVal
    313349 
    314350// Multivariate innovation for one current time-series sample 
     
    319355// first time-series sample of the evaluation interval 
    320356double he[2][Nt]; 
    321 // Log probability density of the value of z for current and proposal 
    322 // evaluations, working values 
    323 double Lzk[2]; 
    324357// Log-likelihood of the innovation for the first time-series sample in current 
    325358// and proposal evalutions, working values and accumulated for each iteration 
     
    372405    // Clear the log-likelihood and normal log-density accumulators of each 
    373406    // evaluation struct for the next pair of evaluations. 
    374     for(k2=0; k2<2; k2++) { 
     407    for(k2=0; k2<2; k2++) 
    375408      se[k2].Lx = 0; 
    376       Lzk[k2] = 0; 
    377409      // Lxk[.] will be set to a value in se[.].Lx that has already been 
    378410      // multivariate-accumulated, so it doesn't need clearing here 
    379     } 
    380411     
    381412    do { 
     
    395426              // First time-series sample for the second evaluation, use a 
    396427              // proposal on z instead of z itself 
    397               val += uniform(-w, +w); 
     428              val = truncnorm(val-w, val+w); 
    398429              zp[k3] = val; 
    399430            } 
    400             // Store the log-density of z for the first time-series sample to 
    401             // compare current vs. proposal 
    402             Lzk[k2] += normLogDensity(val); 
    403431          } 
    404432          PA1(se[k2].z, k3) = val; 
     
    430458    } while (k1<Ns && (val > MIN_DIFF || val < -MIN_DIFF)); 
    431459 
    432     // Metropolis-hastings selection of current or proposal using Lz+Lx for 
    433     // each evaluation 
    434     val = Lzk[1] + se[1].Lx  -  Lzk[0] - se[0].Lx; 
     460    // Metropolis-hastings selection of current or proposal 
     461    val = se[1].Lx  -  se[0].Lx; 
    435462    if(val > 0 || log(uniform(0, 1)) < val) { 
    436463      // Proposal accepted 
     
    486513} 
    487514 
    488 // Compute the result, the integrated P(x|w) over the last half of the 
     515// Compute the result, the integrated P(x|w) over the last 3/4 of the 
    489516// simulations on z 
    490  
    491 // Compute the maximum log density // and save it to subtract from everybody 
     517k0 = (int)(100*ni/400); 
     518 
     519// Compute the maximum log density and save it to subtract from everybody so 
    492520// that the maximum log density is normalized to zero 
    493 val = -HUGE_VAL; 
    494 for(ki=ni/2; ki<ni; ki++) { 
    495   if(Lx[ki] > val) 
    496     val = Lx[ki]; 
    497 } 
    498 // Accumulate the linearized normalized densities, borrowing Lzk[0] to do so 
    499 Lzk[0] = 0; 
    500 for(ki=ni/2; ki<ni; ki++) 
    501   Lzk[0] += exp(Lx[ki] - val); 
     521maxVal = -HUGE_VAL; 
     522for(ki=k0; ki<ni; ki++) { 
     523  if(Lx[ki] > maxVal) 
     524    maxVal = Lx[ki]; 
     525} 
     526// Accumulate the linearized normalized densities 
     527val = 0; 
     528for(ki=k0; ki<ni; ki++) 
     529  val += exp(Lx[ki] - maxVal); 
    502530// ...and return the denormalized, log mean of the linear densities... 
    503 return_val = log(Lzk[0]) + val - log(ni/2); 
     531return_val = log(val) + maxVal - log(ni-k0); 
  • projects/AsynCluster/trunk/svpmc/model.py

    r201 r202  
    187187     
    188188    """ 
    189     keyAttrs = {'y':None, 'wiggle':1.0, 'Ni':30} 
     189    keyAttrs = {'y':None, 'wiggle':1.0, 'Ni':100} 
    190190 
    191191    #--- Properties ----------------------------------------------------------- 
  • projects/AsynCluster/trunk/svpmc/test/test_model.py

    r201 r202  
    318318            self.failUnlessEqual(len(s.unique(z)), N) 
    319319 
     320    def test_support_truncnorm(self): 
     321        pass 
     322        code = """ 
     323        int k; 
     324        for(k=0; k<Nx[0]; k++) 
     325          X1(k) = truncnorm(a, b); 
     326        """ 
     327        Ns = 100 
     328        ranges = ((-1, +1), (-0.5, +1.5), (1.0, 2.0), (3.0, 5.0)) 
     329        fig = self.fig 
     330        spNumBase = 100*len(ranges) + 11 
     331        k = 0 
     332        for a, b in ranges: 
     333            title = "%+3.1f to %+3.1f" % (a, b) 
     334            print "\n%s\n" % title 
     335            x = s.empty(Ns) 
     336            self.inline(code, x=x, a=a, b=b) 
     337            sp = fig.add_subplot(spNumBase+k) 
     338            sp.hist(x, bins=20) 
     339            sp.set_title(title) 
     340            k += 1 
     341        print "\n" 
     342 
    320343    def test_support_matrixMultiply(self): 
    321344        code = """ 
     
    650673 
    651674    def test_Lx(self): 
    652         wiggle = 0.5 
     675        # Wiggle seems fairly critical, best at 0.5-1.0. 
     676        # Tried independent proposals +/- 4.0, didn't work well. 
     677        wiggle = 1.0 
    653678        eValue = 0.97 
    654679        Ns, Ni, Nr = 200, 100, 100 
     
    676701            fig = self._plot(*plotArgs) 
    677702            fig.text(0.05, 0.95, "Best", size='x-large') 
    678          
    679703     
    680704    def test_optimize_Ni(self): 
     
    685709        """ 
    686710        Nr = 1000 
    687         wiggle = 0.5 
     711        wiggle = 1.0 
    688712        eValue = 0.95 
    689713        Ns = 1000