improved per-component BSDF chi-square test
parent
5a40118a44
commit
a5364d02f1
|
@ -95,7 +95,7 @@ public:
|
||||||
ChiSquareTest(int thetaBins = 10, int phiBins = 0, size_t sampleCount = 0);
|
ChiSquareTest(int thetaBins = 10, int phiBins = 0, size_t sampleCount = 0);
|
||||||
|
|
||||||
/// Set the log level
|
/// Set the log level
|
||||||
inline void setLogLevel(ELogLevel logLevel) { m_logLevel = EInfo; }
|
inline void setLogLevel(ELogLevel logLevel) { m_logLevel = logLevel; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Fill the actual and reference bin counts
|
* \brief Fill the actual and reference bin counts
|
||||||
|
|
|
@ -59,9 +59,9 @@ bool ChiSquareTest::runTest(int distParams, Float pvalThresh) {
|
||||||
Log(m_logLevel, "Pooled %i cells with an expected "
|
Log(m_logLevel, "Pooled %i cells with an expected "
|
||||||
"number of < 5 entries!", pooledCells);
|
"number of < 5 entries!", pooledCells);
|
||||||
if (pooledRef < 5) {
|
if (pooledRef < 5) {
|
||||||
Log(EWarn, "Even after pooling, the expected "
|
Log(EWarn, "Even after pooling %i cells, the expected "
|
||||||
"number of entries is < 5 (%f), expect badness!",
|
"number of entries is < 5 (%f), expect badness!",
|
||||||
pooledRef);
|
pooledCells, pooledRef);
|
||||||
}
|
}
|
||||||
Float diff = pooledCounts - pooledRef;
|
Float diff = pooledCounts - pooledRef;
|
||||||
chsq += (diff*diff) / pooledRef;
|
chsq += (diff*diff) / pooledRef;
|
||||||
|
@ -78,7 +78,7 @@ bool ChiSquareTest::runTest(int distParams, Float pvalThresh) {
|
||||||
Log(m_logLevel, pval > 0.01 ? "P-value = %.4f" : "P-value = %e", pval);
|
Log(m_logLevel, pval > 0.01 ? "P-value = %.4f" : "P-value = %e", pval);
|
||||||
|
|
||||||
if (pval < pvalThresh) {
|
if (pval < pvalThresh) {
|
||||||
Log(EWarn, "Rejecting the null hypothesis");
|
Log(EWarn, "Rejecting the null hypothesis (P-value=%e)", pval);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -36,13 +36,14 @@ public:
|
||||||
|
|
||||||
class BSDFFunctor {
|
class BSDFFunctor {
|
||||||
public:
|
public:
|
||||||
BSDFFunctor(const BSDF *bsdf, Random *random, const Vector &wi)
|
BSDFFunctor(const BSDF *bsdf, Random *random, const Vector &wi, int component = -1)
|
||||||
: m_bsdf(bsdf), m_random(random), m_wi(wi) { }
|
: m_bsdf(bsdf), m_random(random), m_wi(wi), m_component(component) { }
|
||||||
|
|
||||||
std::pair<Vector, Float> generateSample() {
|
std::pair<Vector, Float> generateSample() {
|
||||||
Point2 sample(m_random->nextFloat(), m_random->nextFloat());
|
Point2 sample(m_random->nextFloat(), m_random->nextFloat());
|
||||||
Intersection its;
|
Intersection its;
|
||||||
BSDFQueryRecord bRec(its);
|
BSDFQueryRecord bRec(its);
|
||||||
|
bRec.component = m_component;
|
||||||
bRec.wi = m_wi;
|
bRec.wi = m_wi;
|
||||||
m_bsdf->sample(bRec, sample);
|
m_bsdf->sample(bRec, sample);
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ public:
|
||||||
Float pdf(const Vector &wo) const {
|
Float pdf(const Vector &wo) const {
|
||||||
Intersection its;
|
Intersection its;
|
||||||
BSDFQueryRecord bRec(its);
|
BSDFQueryRecord bRec(its);
|
||||||
|
bRec.component = m_component;
|
||||||
bRec.wi = m_wi;
|
bRec.wi = m_wi;
|
||||||
bRec.wo = wo;
|
bRec.wo = wo;
|
||||||
return m_bsdf->pdf(bRec);
|
return m_bsdf->pdf(bRec);
|
||||||
|
@ -60,6 +62,7 @@ public:
|
||||||
ref<const BSDF> m_bsdf;
|
ref<const BSDF> m_bsdf;
|
||||||
ref<Random> m_random;
|
ref<Random> m_random;
|
||||||
Vector m_wi;
|
Vector m_wi;
|
||||||
|
int m_component;
|
||||||
};
|
};
|
||||||
|
|
||||||
void test01_BSDF() {
|
void test01_BSDF() {
|
||||||
|
@ -67,17 +70,18 @@ public:
|
||||||
ref<Scene> scene = loadScene("data/tests/test_bsdf.xml");
|
ref<Scene> scene = loadScene("data/tests/test_bsdf.xml");
|
||||||
|
|
||||||
const std::vector<ConfigurableObject *> objects = scene->getReferencedObjects();
|
const std::vector<ConfigurableObject *> objects = scene->getReferencedObjects();
|
||||||
size_t thetaBins = 10, wiSamples = 5;
|
size_t thetaBins = 10, wiSamples = 20, failureCount = 0, testCount = 0;
|
||||||
ref<Random> random = new Random();
|
ref<Random> random = new Random();
|
||||||
|
|
||||||
|
Log(EInfo, "Verifying BSDF sampling routines ..");
|
||||||
for (size_t i=0; i<objects.size(); ++i) {
|
for (size_t i=0; i<objects.size(); ++i) {
|
||||||
if (!objects[i]->getClass()->derivesFrom(MTS_CLASS(BSDF)))
|
if (!objects[i]->getClass()->derivesFrom(MTS_CLASS(BSDF)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const BSDF *bsdf = static_cast<const BSDF *>(objects[i]);
|
const BSDF *bsdf = static_cast<const BSDF *>(objects[i]);
|
||||||
|
|
||||||
Log(EInfo, "Checking sampling with %i different incident directions, BSDF:\n%s",
|
Log(EInfo, "Processing BSDF model %s", bsdf->toString().c_str());
|
||||||
wiSamples, bsdf->toString().c_str());
|
Log(EInfo, "Checking the combined model for %i incident directions", wiSamples);
|
||||||
|
|
||||||
/* Test for a number of different incident directions */
|
/* Test for a number of different incident directions */
|
||||||
for (size_t j=0; j<wiSamples; ++j) {
|
for (size_t j=0; j<wiSamples; ++j) {
|
||||||
|
@ -90,6 +94,7 @@ public:
|
||||||
|
|
||||||
BSDFFunctor functor(bsdf, random, wi);
|
BSDFFunctor functor(bsdf, random, wi);
|
||||||
ref<ChiSquareTest> chiSqr = new ChiSquareTest(thetaBins);
|
ref<ChiSquareTest> chiSqr = new ChiSquareTest(thetaBins);
|
||||||
|
chiSqr->setLogLevel(EDebug);
|
||||||
|
|
||||||
// Initialize the tables used by the chi-square test
|
// Initialize the tables used by the chi-square test
|
||||||
chiSqr->fill(
|
chiSqr->fill(
|
||||||
|
@ -97,16 +102,58 @@ public:
|
||||||
boost::bind(&BSDFFunctor::pdf, functor, _1)
|
boost::bind(&BSDFFunctor::pdf, functor, _1)
|
||||||
);
|
);
|
||||||
|
|
||||||
// (the folowing assumes that the distribution has 1 parameter, e.g. exponent value)
|
// (the following assumes that the distribution has 1 parameter, e.g. exponent value)
|
||||||
if (!chiSqr->runTest(1)) {
|
if (!chiSqr->runTest(1)) {
|
||||||
// Optional: dump the tables to a MATLAB file for external analysis
|
std::string filename = formatString("failure_%i.m", failureCount++);
|
||||||
chiSqr->dumpTables("failure.m");
|
chiSqr->dumpTables(filename);
|
||||||
failAndContinue("Oh oh, the chi-square test failed! Dumped the contingency tables to 'failure.m'");
|
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
|
||||||
|
"issue for wi=%s. Dumped the contingency tables to '%s' for user analysis",
|
||||||
|
wi.toString().c_str(), filename.c_str()));
|
||||||
} else {
|
} else {
|
||||||
succeed();
|
succeed();
|
||||||
}
|
}
|
||||||
|
++testCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bsdf->getComponentCount() > 1) {
|
||||||
|
for (int comp=0; comp<bsdf->getComponentCount(); ++comp) {
|
||||||
|
Log(EInfo, "Checking BSDF component %i", comp);
|
||||||
|
|
||||||
|
/* Test for a number of different incident directions */
|
||||||
|
for (size_t j=0; j<wiSamples; ++j) {
|
||||||
|
Vector wi;
|
||||||
|
|
||||||
|
if (bsdf->getType(comp) & (BSDF::EDiffuseTransmission | BSDF::EGlossyTransmission))
|
||||||
|
wi = squareToSphere(Point2(random->nextFloat(), random->nextFloat()));
|
||||||
|
else
|
||||||
|
wi = squareToHemispherePSA(Point2(random->nextFloat(), random->nextFloat()));
|
||||||
|
|
||||||
|
BSDFFunctor functor(bsdf, random, wi, comp);
|
||||||
|
ref<ChiSquareTest> chiSqr = new ChiSquareTest(thetaBins);
|
||||||
|
chiSqr->setLogLevel(EDebug);
|
||||||
|
|
||||||
|
// Initialize the tables used by the chi-square test
|
||||||
|
chiSqr->fill(
|
||||||
|
boost::bind(&BSDFFunctor::generateSample, functor),
|
||||||
|
boost::bind(&BSDFFunctor::pdf, functor, _1)
|
||||||
|
);
|
||||||
|
|
||||||
|
// (the following assumes that the distribution has 1 parameter, e.g. exponent value)
|
||||||
|
if (!chiSqr->runTest(1)) {
|
||||||
|
std::string filename = formatString("failure_%i.m", failureCount++);
|
||||||
|
chiSqr->dumpTables(filename);
|
||||||
|
failAndContinue(formatString("Uh oh, the chi-square test indicates a potential "
|
||||||
|
"issue for wi=%s. Dumped the contingency tables to '%s' for user analysis",
|
||||||
|
wi.toString().c_str(), filename.c_str()));
|
||||||
|
} else {
|
||||||
|
succeed();
|
||||||
|
}
|
||||||
|
++testCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log(EInfo, "%i/%i BSDF checks succeeded", testCount-failureCount, testCount);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue