MultipleImportanceSampler.h

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @class  MultipleImportanceSampler
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    
00013       The goal of importance sampling is to reduce variance while 
00014    approximating the integral of f over D by drawing random samples across D 
00015    according to some probability density function p which is proportional to 
00016    f.  By drawing more samples from the regions where f is large (concentrating
00017    our sampling effort on the "important" regions of the domain), and similarly
00018    drawing less samples from the regions where f is small (focusing less effort
00019    in the "unimportant" regions of the domain), the variance of our estimate 
00020    overall is reduced, as long as we compensate for our uneven sampling rate 
00021    by weighting each sample by the inverse probability with which it was 
00022    sampled.
00023       Think of importance sampling this way:  if we have only one shot at 
00024    sampling f (only one sample because of very limited 'resources'), we would 
00025    like to concentrate that one sample in the region of the domain that will 
00026    contribute the most to the value of the integral we are ultimately trying 
00027    to approximate.  By biasing our sampling technique to weigh "important", 
00028    "large" regions of the domain with respect to f, we get more bang for our
00029    buck and correspondingly end up with a much lower variance estimator. If 
00030    we were to instead naively sample uniformly across the domain, D, there's 
00031    a good chance that our one, precious sample would be wasted by sampling 
00032    a location, x, that is unimportant, where f(x) is relatively small.
00033       A perfect estimator would take samples from a distribution p, across D, 
00034    whose probabilities were distributed directly proportional to f.  This is, 
00035    however, unreasonable, since if we knew the exact values of f across D, 
00036    we wouldn't have to approximate the integral of f over D in the first place.
00037    We can, however, still greatly reduce variance by using knowledge about 
00038    f to guide our sampling process and instead, sample according to either 
00039    an approximation of f, or possibly according to some factorization of f 
00040    into separate functions f1, f2, etc, some of which may be easier to draw 
00041    samples from.  As long as our sampling process attempts to draw samples 
00042    from areas in D where f is "known" to be large and avoids regions in D 
00043    where f is "known" to be small, our sampler will be more efficient and 
00044    our overall variance will be reduced.
00045    
00046       Multiple importance sampling generalizes this one step further. Say 
00047    we have n different sampling distributions p1,p2,...,pn, and our function 
00048    f, may be separated or factored into several functions, f1,f2,...fm. By 
00049    designing different sampling distributions to focus on one or more of the 
00050    simpler functions, fi, we can combine samples from the different sampling 
00051    distributions, each of which may be better at estimating some important 
00052    component (subfunction) of f, we can gain a much better final sampling 
00053    distribution, p, which captures all of the relevant aspects of f in an 
00054    intuitive, modularized manner (where each pi can be tuned towards 
00055    capturing a different fi).  How to go about combining samples from n 
00056    distributions, all or some of which may be good or bad estimators of f, 
00057    is a very difficult problem in this generic of a setting.
00058       Veach and Guibas (1995) showed several provably good ways of optimally 
00059    combining sampling techniques for Monte Carlo integration.  This class 
00060    implements their multiple importance sampling model, including several 
00061    heuristics they gave which attempt to combine samples in slightly 
00062    different ways that may work better in one situation versus another.
00063    These include the balance, cutoff, power, and maximum heuristics.
00064    
00065    @note for more information and theoretical details, see
00066       Veach and Guibas. Optimally Combining Sampling Techniques for Monte 
00067       Carlo Rendering. In Proceedings of the 22nd Annual Conference on 
00068       Computer Graphics and interactive Techniques S.G. Mair and R. Cook, 
00069       Eds. SIGGRAPH '95. ACM, New York, NY, 419-428.
00070    
00071    @see http://www-graphics.stanford.edu/papers/combine/
00072    <!-------------------------------------------------------------------->**/
00073 
00074 #ifndef MULTIPLE_IMPORTANCE_SAMPLER_H_
00075 #define MULTIPLE_IMPORTANCE_SAMPLER_H_
00076 
00077 #include <stats/WeightedEvent.h>
00078 #include <utils/PropertyMap.h>
00079 
00080 class Sampler;
00081 
00082 DECLARE_STL_TYPEDEF(std::vector<Sampler*>, SamplerList);
00083 DECLARE_STL_TYPEDEF(std::vector<unsigned>, IntList);
00084 
00085 class MultipleImportanceSampler : public PropertyMap {
00086    /// @note ni, n, and N use the same notation from Veach and Guibas' paper
00087    
00088    public:
00089       ///@name Constructors
00090       //@{-----------------------------------------------------------------
00091       
00092       /**
00093        * @param ni is the constant number of samples to take per sampler
00094        */
00095       inline MultipleImportanceSampler(const SamplerList &samplers, 
00096                                        unsigned ni = 1)
00097          : m_samplers(samplers), m_N(samplers.size()), m_n(m_N * ni), 
00098            m_ni(m_N, ni), m_computeWeightFunc(NULL)
00099       { }
00100       
00101       /**
00102        * @param ni holds the variable number of samples to take per sampler
00103        */
00104       inline MultipleImportanceSampler(const SamplerList &samplers, 
00105                                        const IntList &ni)
00106          : m_samplers(samplers), m_N(samplers.size()), m_n(0), m_ni(ni), 
00107            m_computeWeightFunc(NULL)
00108       {
00109          ASSERT(m_N == m_ni.size());
00110          
00111          FOREACH(IntListConstIter, m_ni, iter) {
00112             m_n += *iter;
00113          }
00114       }
00115       
00116       virtual ~MultipleImportanceSampler() 
00117       { }
00118       
00119       
00120       //@}-----------------------------------------------------------------
00121       ///@name Initialization
00122       //@{-----------------------------------------------------------------
00123       
00124       /**
00125        * @brief
00126        *    Initializes the weight computation function based on this 
00127        * class' PropertyMap
00128        * 
00129        * @note defaults to balance heuristic
00130        */
00131       virtual void init();
00132       
00133       
00134       //@}-----------------------------------------------------------------
00135       ///@name Main usage interface
00136       //@{-----------------------------------------------------------------
00137       
00138       /**
00139        * @brief
00140        *    Generates ni samples from each sampler pi in { p1,p1,...,pn }, 
00141        * along with sample weights, and stores the N weighted events in 
00142        * the out parameter @p results
00143        * 
00144        * @note 'results' is first cleared before adding any samples
00145        */
00146       virtual void sample(WeightedEventList &results);
00147       
00148       
00149       //@}-----------------------------------------------------------------
00150       
00151    protected:
00152       typedef void (MultipleImportanceSampler::*ComputeWeightFunc) 
00153          (WeightedEvent &event, unsigned i);
00154       
00155       // weighting heuristics
00156       virtual void _computeWeightBalance(WeightedEvent &event, unsigned i);
00157       virtual void _computeWeightCutoff (WeightedEvent &event, unsigned i);
00158       virtual void _computeWeightPower  (WeightedEvent &event, unsigned i);
00159       virtual void _computeWeightMaximum(WeightedEvent &event, unsigned i);
00160       
00161    protected:
00162       /// list of distributions from which to draw samples from
00163       SamplerList m_samplers;
00164       
00165       /// number of sampling distributions in m_samplers
00166       unsigned    m_N;
00167       
00168       /// total number of samples
00169       unsigned    m_n;
00170       
00171       /// sampler-by-sampler breakdown of number of samples
00172       IntList     m_ni;
00173       
00174       /// weight computation for individual samples (see init())
00175       ComputeWeightFunc m_computeWeightFunc;
00176       
00177       union {
00178          /// input to power heuristic
00179          real_t      m_beta;
00180          
00181          /// input to alpha heuristic
00182          real_t      m_alpha;
00183       };
00184 };
00185 
00186 #endif // MULTIPLE_IMPORTANCE_SAMPLER_H_
00187 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6