Skip to content

Commit d6dfc47

Browse files
authored
[ML] Fix for CPoissonMeanConjugate sampling error. (#335) (#338)
Fix for "sample out of bounds" error generated from CPoissonMeanConjugate Backports #335
1 parent dde0e18 commit d6dfc47

6 files changed

+101
-0
lines changed

docs/CHANGELOG.asciidoc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@
2828
2929
//=== Regressions
3030
31+
== {es} version 6.6.0
32+
33+
=== Breaking Changes
34+
35+
=== Deprecations
36+
37+
=== New Features
38+
39+
=== Enhancements
40+
41+
=== Bug Fixes
42+
43+
Fix cause of "Sample out of bounds" error message (See {ml-pull}355[355].}
44+
45+
=== Regressions
46+
3147
== {es} version 6.5.3
3248
3349
=== Bug Fixes

lib/maths/CPoissonMeanConjugate.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,9 @@ void CPoissonMeanConjugate::sampleMarginalLikelihood(std::size_t numberSamples,
646646
// Sanity check the sample: should be in the distribution support.
647647
if (sample >= support.first && sample <= support.second) {
648648
samples.push_back(sample);
649+
} else if (sample < support.first) {
650+
// Extremely rarely the variance is large and the offset is 0, resulting in a negative sample.
651+
// We discard these negative samples as they are logically incongruous for a counting distribution.
649652
} else {
650653
LOG_ERROR(<< "Sample out of bounds: sample = " << sample << ", support = ["
651654
<< support.first << "," << support.second << "]"

lib/maths/unittest/CPoissonMeanConjugateTest.cc

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,54 @@ void CPoissonMeanConjugateTest::testSampleMarginalLikelihood() {
494494
}
495495
}
496496

497+
void CPoissonMeanConjugateTest::testSampleMarginalLikelihoodInSupportBounds() {
498+
// Here we test that the retrieved samples are
499+
// a) positive
500+
// b) monotonically increasing
501+
// c) No ERROR log messages are generated
502+
// The input sample and weight are chosen to be ones that generate
503+
// an initial sample that is less than an offset value of 0.0
504+
505+
const char* logFile = "test.log";
506+
507+
std::remove(logFile);
508+
// log at level ERROR only
509+
CPPUNIT_ASSERT(ml::core::CLogger::instance().reconfigureFromFile(
510+
"testfiles/testLogErrorsLog4cxx.properties"));
511+
512+
CPoissonMeanConjugate filter(CPoissonMeanConjugate::nonInformativePrior());
513+
514+
TDouble1Vec sampleVec(1, 283.3232);
515+
maths_t::TDoubleWeightsAry1Vec weightVec(1, maths_t::countWeight(0.0206505));
516+
517+
filter.addSamples(sampleVec, weightVec);
518+
519+
std::size_t numberSampled = 50u;
520+
TDouble1Vec sampled;
521+
522+
filter.sampleMarginalLikelihood(numberSampled, sampled);
523+
524+
double prevSample{0.0};
525+
for (double sample : sampled) {
526+
CPPUNIT_ASSERT(sample > prevSample);
527+
CPPUNIT_ASSERT(sample >= 0.0);
528+
prevSample = sample;
529+
}
530+
531+
// Revert to the default properties for the test framework - very similar to the hardcoded default.
532+
CPPUNIT_ASSERT(ml::core::CLogger::instance().reconfigureFromFile("testfiles/log4cxx.properties"));
533+
534+
std::ifstream log(logFile);
535+
CPPUNIT_ASSERT(log.is_open());
536+
char line[256];
537+
while (log.getline(line, 256)) {
538+
LOG_INFO(<< "Got '" << line << "'");
539+
CPPUNIT_ASSERT(false);
540+
}
541+
log.close();
542+
std::remove(logFile);
543+
}
544+
497545
void CPoissonMeanConjugateTest::testCdf() {
498546
// Test error cases.
499547
//
@@ -960,6 +1008,9 @@ CppUnit::Test* CPoissonMeanConjugateTest::suite() {
9601008
&CPoissonMeanConjugateTest::testSampleMarginalLikelihood));
9611009
suiteOfTests->addTest(new CppUnit::TestCaller<CPoissonMeanConjugateTest>(
9621010
"CPoissonMeanConjugateTest::testCdf", &CPoissonMeanConjugateTest::testCdf));
1011+
suiteOfTests->addTest(new CppUnit::TestCaller<CPoissonMeanConjugateTest>(
1012+
"CPoissonMeanConjugateTest::testSampleMarginalLikelihoodInSupportBounds",
1013+
&CPoissonMeanConjugateTest::testSampleMarginalLikelihoodInSupportBounds));
9631014
suiteOfTests->addTest(new CppUnit::TestCaller<CPoissonMeanConjugateTest>(
9641015
"CPoissonMeanConjugateTest::testProbabilityOfLessLikelySamples",
9651016
&CPoissonMeanConjugateTest::testProbabilityOfLessLikelySamples));

lib/maths/unittest/CPoissonMeanConjugateTest.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class CPoissonMeanConjugateTest : public CppUnit::TestFixture {
1515
void testPropagation();
1616
void testMeanEstimation();
1717
void testMarginalLikelihood();
18+
void testSampleMarginalLikelihoodInSupportBounds();
1819
void testMarginalLikelihoodMode();
1920
void testMarginalLikelihoodVariance();
2021
void testSampleMarginalLikelihood();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Set root logger level to DEBUG and its only appender to A1.
2+
log4j.rootLogger=DEBUG, A1
3+
4+
# A1 is set to be a ConsoleAppender.
5+
log4j.appender.A1=org.apache.log4j.ConsoleAppender
6+
log4j.appender.A1.Target=System.err
7+
8+
# A1 uses PatternLayout.
9+
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
10+
log4j.appender.A1.layout.ConversionPattern=%d %d{%Z} [%P] %-5p %F@%L %m%n
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Set root logger level to INFO and its only appender to A1.
2+
log4j.rootLogger=DEBUG, A1
3+
4+
# Also set up a logger named after the log identifier of the program, with
5+
# appender A2.
6+
log4j.logger.%N=ERROR, A2
7+
8+
# A1 is set to be a ConsoleAppender.
9+
log4j.appender.A1=org.apache.log4j.ConsoleAppender
10+
log4j.appender.A1.Target=System.err
11+
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
12+
log4j.appender.A1.layout.ConversionPattern=%d %d{%Z} [%P] %-5p %F@%L %m%n
13+
14+
# A2 is set to log to a rolling file in a current directory.
15+
log4j.appender.A2=org.apache.log4j.RollingFileAppender
16+
log4j.appender.A2.File=test.log
17+
log4j.appender.A2.MaxFileSize=10MB
18+
log4j.appender.A2.MaxBackupIndex=1
19+
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
20+
log4j.appender.A2.layout.ConversionPattern=%d %d{%Z} [%P] %-5p %F@%L %m%n

0 commit comments

Comments
 (0)