MultipleImportanceSampler.cpp
Go to the documentation of this file.00001 /**<!--------------------------------------------------------------------> 00002 @file MultipleImportanceSampler.cpp 00003 @author Travis Fischer (fisch0920@gmail.com) 00004 @author Matthew Jacobs (jacobs.mh@gmail.com) 00005 @date Fall 2008 00006 00007 @brief 00008 "Optimally" combines samples taken from multiple sampling distributions 00009 with respect to a function, 'f', whose value we are trying to integate 00010 over a given domain,'D'. D is assumed to be the union of the domains of 00011 the individual underlying distributions. 00012 The goal of importance sampling is to reduce variance while 00013 approximating the integral of f over D by drawing random samples across D 00014 according to some probability density function p which is proportional to 00015 f. By drawing more samples from the regions where f is large (concentrating 00016 our sampling effort on the "important" regions of the domain), and similarly 00017 drawing less samples from the regions where f is small (focusing less effort 00018 in the "unimportant" regions of the domain), the variance of our estimate 00019 overall is reduced, as long as we compensate for our uneven sampling rate 00020 by weighting each sample by the inverse probability with which it was 00021 sampled. 00022 Think of importance sampling this way: if we have only one shot at 00023 sampling f (only one sample because of very limited 'resources'), we would 00024 like to concentrate that one sample in the region of the domain that will 00025 contribute the most to the value of the integral we are ultimately trying 00026 to approximate. By biasing our sampling technique to weigh "important", 00027 "large" regions of the domain with respect to f, we get more bang for our 00028 buck and correspondingly end up with a much lower variance estimator. If 00029 we were to instead naively sample uniformly across the domain, D, there's 00030 a good chance that our one, precious sample would be wasted by sampling 00031 a location, x, that is unimportant, where f(x) is relatively small. 00032 A perfect estimator would take samples from a distribution p, across D, 00033 whose probabilities were distributed directly proportional to f. This is, 00034 however, unreasonable, since if we knew the exact values of f across D, 00035 we wouldn't have to approximate the integral of f over D in the first place. 00036 We can, however, still greatly reduce variance by using knowledge about 00037 f to guide our sampling process and instead, sample according to either 00038 an approximation of f, or possibly according to some factorization of f 00039 into separate functions f1, f2, etc, some of which may be easier to draw 00040 samples from. As long as our sampling process attempts to draw samples 00041 from areas in D where f is "known" to be large and avoids regions in D 00042 where f is "known" to be small, our sampler will be more efficient and 00043 our overall variance will be reduced. 00044 00045 Multiple importance sampling generalizes this one step further. Say 00046 we have n different sampling distributions p1,p2,...,pn, and our function 00047 f, may be separated or factored into several functions, f1,f2,...fm. By 00048 designing different sampling distributions to focus on one or more of the 00049 simpler functions, fi, we can combine samples from the different sampling 00050 distributions, each of which may be better at estimating some important 00051 component (subfunction) of f, we can gain a much better final sampling 00052 distribution, p, which captures all of the relevant aspects of f in an 00053 intuitive, modularized manner (where each pi can be tuned towards 00054 capturing a different fi). How to go about combining samples from n 00055 distributions, all or some of which may be good or bad estimators of f, 00056 is a very difficult problem in this generic of a setting. 00057 Veach and Guibas (1995) showed several provably good ways of optimally 00058 combining sampling techniques for Monte Carlo integration. This class 00059 implements their multiple importance sampling model, including several 00060 heuristics they gave which attempt to combine samples in slightly 00061 different ways that may work better in one situation versus another. 00062 These include the balance, cutoff, power, and maximum heuristics. 00063 00064 @note for more information and theoretical details, see 00065 Veach and Guibas. Optimally Combining Sampling Techniques for Monte 00066 Carlo Rendering. In Proceedings of the 22nd Annual Conference on 00067 Computer Graphics and interactive Techniques S.G. Mair and R. Cook, 00068 Eds. SIGGRAPH '95. ACM, New York, NY, 419-428. 00069 00070 @see http://www-graphics.stanford.edu/papers/combine/ 00071 <!-------------------------------------------------------------------->**/ 00072 00073 #include "MultipleImportanceSampler.h" 00074 #include "Sampler.h" 00075 00076 void MultipleImportanceSampler::init() { 00077 const std::string &weightFunc = getValue<std::string>("weightFunc", 00078 "balance"); 00079 00080 if (weightFunc == "balance") { 00081 m_computeWeightFunc = &MultipleImportanceSampler::_computeWeightBalance; 00082 } else if (weightFunc == "power") { 00083 m_computeWeightFunc = &MultipleImportanceSampler::_computeWeightPower; 00084 00085 m_beta = getValue<real_t>("beta", 2.0); 00086 } else if (weightFunc == "cutoff") { 00087 m_computeWeightFunc = &MultipleImportanceSampler::_computeWeightCutoff; 00088 00089 m_alpha = getValue<real_t>("alpha", 0.1); 00090 } else { 00091 ASSERT(weightFunc == "maximum"); 00092 m_computeWeightFunc = &MultipleImportanceSampler::_computeWeightMaximum; 00093 } 00094 } 00095 00096 void MultipleImportanceSampler::sample(WeightedEventList &results) { 00097 ASSERT(m_computeWeightFunc != NULL); 00098 results.clear(); 00099 00100 for(unsigned i = m_n; i--;) { 00101 Sampler *sampler = m_samplers[i]; 00102 const unsigned ni = m_ni[i]; 00103 00104 for(unsigned j = ni; j--;) { 00105 results.push_back(WeightedEvent(sampler->sample())); 00106 ((this)->*(m_computeWeightFunc))(results.back(), i); 00107 } 00108 } 00109 } 00110 00111 void MultipleImportanceSampler::_computeWeightBalance(WeightedEvent &e, 00112 unsigned i) 00113 { 00114 ASSERT(i < m_n); 00115 real_t num = 0, den = 0; 00116 00117 // TODO: this is incorrect; m_ni[j] doesn't exist cause m_n goes up too 00118 // high!!! 00119 NYI(); 00120 for(unsigned j = m_n; j--;) { 00121 if (i == j) 00122 den += (num = ((m_ni[j] / real_t(m_N)) * e.event.getPdf())); 00123 else 00124 den += (m_ni[j] / real_t(m_N)) * m_samplers[i]->getPdf(e.event); 00125 } 00126 00127 ASSERT(den > 0); 00128 e.weight = num / den; 00129 } 00130 00131 void MultipleImportanceSampler::_computeWeightCutoff(WeightedEvent &e, 00132 unsigned i) 00133 { 00134 ASSERT(i < m_n); 00135 const real_t pi = e.event.getPdf(); 00136 real_t pMax = pi; 00137 00138 for(unsigned j = m_n; j--;) { 00139 const real_t p = (i == j ? pi : m_samplers[i]->getPdf(e.event)); 00140 pMax = MAX(p, pMax); 00141 } 00142 00143 pMax *= m_alpha; 00144 e.weight = 0; 00145 00146 if (pi >= pMax) { 00147 for(unsigned j = m_n; j--;) { 00148 const real_t p = (i == j ? pi : m_samplers[i]->getPdf(e.event)); 00149 00150 if (p >= pMax) 00151 e.weight += p; 00152 } 00153 00154 e.weight = pi / e.weight; 00155 } // else set weight to zero (disregards samples below a cutoff threshold) 00156 } 00157 00158 void MultipleImportanceSampler::_computeWeightPower(WeightedEvent &e, 00159 unsigned i) 00160 { 00161 ASSERT(i < m_n); 00162 const real_t pi = pow(e.event.getPdf(), m_beta); 00163 00164 e.weight = 0; 00165 for(unsigned j = m_n; j--;) { 00166 const real_t p = (i == j ? pi : pow(m_samplers[i]->getPdf(e.event), m_beta)); 00167 00168 e.weight += p; 00169 } 00170 00171 e.weight = pi / e.weight; 00172 } 00173 00174 void MultipleImportanceSampler::_computeWeightMaximum(WeightedEvent &e, 00175 unsigned i) 00176 { 00177 ASSERT(i < m_n); 00178 const real_t pi = e.event.getPdf(); 00179 real_t pMax = pi; 00180 00181 for(unsigned j = m_n; j--;) { 00182 const real_t p = (i == j ? pi : m_samplers[i]->getPdf(e.event)); 00183 pMax = MAX(p, pMax); 00184 } 00185 00186 e.weight = (pi == pMax); 00187 } 00188
Generated on 28 Feb 2009 for Milton by
1.5.6