Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
chisquare.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_CHISQUARE_H_)
21 #define __MITSUBA_CORE_CHISQUARE_H_
22 
23 #include <mitsuba/render/common.h>
24 #include <boost/tuple/tuple.hpp>
25 #include <boost/function.hpp>
26 
28 
29 /// Minimum expected cell frequency. Cells below this value will be pooled
30 #define CHISQR_MIN_EXP_FREQUENCY 5
31 
32 /**
33  * \brief Chi-square goodness-of-fit test on the sphere
34  *
35  * This class performs a chi-square goodness-of-fit test of the null hypothesis
36  * that a specified sampling procedure produces samples that are distributed
37  * according to a supplied density function. This is very useful to verify BRDF
38  * and phase function sampling codes for their correctness. Currently, it
39  * supports both 2D and discrete sampling methods and mixtures thereof.
40  *
41  * This implementation works by generating a large batch of samples, which are
42  * then accumulated into rectangular bins in spherical coordinates. To obtain
43  * reference bin counts, the provided density function is numerically
44  * integrated over the area of each bin. Comparing the actual and reference
45  * bin counts yields the desired test statistic.
46  *
47  * Given a probability distribution with the following interface
48  *
49  * \code
50  * class MyDistribution {
51  * // Sample a (optionally weighted) direction. A non-unity weight
52  * // in the return value is needed when the sampling distribution
53  * // doesn't exactly match the implementation in pdf()
54  * boost::tuple<Vector, Float, EMeasure> generateSample() const;
55  *
56  * /// Compute the probability density for the specified direction and measure
57  * Float pdf(const Vector &direction, EMeasure) const;
58  * };
59  * \endcode
60  *
61  * the code in this class might be used as follows
62  *
63  * \code
64  * MyDistribution myDistrInstance;
65  * ChiSquare chiSqr;
66  *
67  * // Initialize the tables used by the chi-square test
68  * chiSqr.fill(
69  * boost::bind(&MyDistribution::generateSample, myDistrInstance),
70  * boost::bind(&MyDistribution::pdf, myDistrInstance, _1, _2)
71  * );
72  *
73  * // Optional: dump the tables to a MATLAB file for external analysis
74  * chiSqr.dumpTables("debug.m");
75  *
76  * if (!chiSqr.runTest())
77  * Log(EError, "Uh oh -- test failed, the implementation is probably incorrect!");
78  * \endcode
79  * \ingroup libcore
80  */
82 public:
83  /// Possible outcomes in \ref runTest()
84  enum ETestResult {
85  /// The null hypothesis was rejected
86  EReject = 0,
87  /// The null hypothesis was accepted
88  EAccept = 1,
89  /// The degrees of freedom were too low
90  ELowDoF = 2
91  };
92 
93  /**
94  * \brief Create a new Chi-square test instance with the given
95  * resolution and sample count
96  *
97  * \param thetaBins
98  * Number of bins wrt. latitude. The default is 10
99  *
100  * \param phiBins
101  * Number of bins wrt. azimuth. The default is to use
102  * twice the number of \c thetaBins
103  *
104  * \param numTests
105  * Number of independent tests that will be performed. This
106  * is used to compute the Sidak-correction factor.
107  *
108  * \param sampleCount
109  * Number of samples to be used when computing the bin
110  * values. The default is \c thetaBins*phiBins*5000
111  */
112  ChiSquare(int thetaBins = 10, int phiBins = 0,
113  int numTests = 1, size_t sampleCount = 0);
114 
115  /// Get the log level
116  inline ELogLevel getLogLevel() const { return m_logLevel; }
117 
118  /// Set the log level
119  inline void setLogLevel(ELogLevel logLevel) { m_logLevel = logLevel; }
120 
121  /**
122  * \brief Set the tolerance threshold for bins with very low
123  * aggregate probabilities
124  *
125  * When the Chi-square test integrates the supplied probability
126  * density function over the support of a bin and determines that
127  * the aggregate bin probability is zero, the test would ordinarily
128  * fail if as much as one sample is placed in that bin in the
129  * subsequent sampling step. However, due to various numerical
130  * errors in a system based on finite-precision arithmetic, it
131  * may be a good idea to tolerate at least a few samples without
132  * immediately rejecting the null hypothesis. This parameter
133  * sets this threshold. The default value is \c number-of-samples*1e-4f
134  */
135  inline void setTolerance(Float tolerance) { m_tolerance = tolerance; }
136 
137  /**
138  * \brief Fill the actual and reference bin counts
139  *
140  * Please see the class documentation for a description
141  * on how to invoke this function
142  */
143  void fill(
144  const boost::function<boost::tuple<Vector, Float, EMeasure>()> &sampleFn,
145  const boost::function<Float (const Vector &, EMeasure)> &pdfFn);
146 
147  /**
148  * \brief Dump the bin counts to a file using MATLAB format
149  */
150  void dumpTables(const fs::path &filename);
151 
152  /**
153  * \brief Perform the actual chi-square test
154  *
155  * \param pvalThresh
156  * The implementation will reject the null hypothesis
157  * when the computed p-value lies below this parameter
158  * (default: 0.01f)
159  *
160  * \return A status value of type \ref ETestResult
161  */
162  ETestResult runTest(Float pvalThresh = 0.01f);
163 
165 protected:
166  /// Release all memory
167  virtual ~ChiSquare();
168 
169  /// Functor to evaluate the pdf values in parallel using OpenMP
170  static void integrand(
171  const boost::function<Float (const Vector &, EMeasure)> &pdfFn,
172  size_t nPts, const Float *in, Float *out) {
173  #if defined(MTS_OPENMP)
174  #pragma omp parallel for
175  #endif
176  for (int i=0; i<(int) nPts; ++i)
177  out[i] = pdfFn(sphericalDirection(in[2*i], in[2*i+1]), ESolidAngle)
178  * std::sin(in[2*i]);
179  }
180 private:
181  ELogLevel m_logLevel;
182  Float m_tolerance;
183  int m_thetaBins, m_phiBins;
184  int m_numTests;
185  size_t m_sampleCount;
186  Float *m_table;
187  Float *m_refTable;
188 };
189 
191 
192 #endif /* __MITSUBA_CORE_CHISQUARE_H_ */
void setTolerance(Float tolerance)
Set the tolerance threshold for bins with very low aggregate probabilities.
Definition: chisquare.h:135
ETestResult
Possible outcomes in runTest()
Definition: chisquare.h:84
Chi-square goodness-of-fit test on the sphere.
Definition: chisquare.h:81
#define MTS_EXPORT_CORE
Definition: getopt.h:29
void setLogLevel(ELogLevel logLevel)
Set the log level.
Definition: chisquare.h:119
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
EMeasure
A list of measures that are associated with various sampling methods in Mitsuba.
Definition: common.h:56
ELogLevel getLogLevel() const
Get the log level.
Definition: chisquare.h:116
Solid angle measure.
Definition: common.h:60
#define MTS_DECLARE_CLASS()
This macro must be used in the initial definition in classes that derive from Object.
Definition: class.h:158
MTS_EXPORT_CORE Vector sphericalDirection(Float theta, Float phi)
Convert spherical coordinates to a direction.
ELogLevel
Available Log message types.
Definition: formatter.h:28
Definition: fwd.h:96
Parent of all Mitsuba classes.
Definition: object.h:38
#define MTS_NAMESPACE_END
Definition: platform.h:138