Fix two bugs on how RightContinuousStepFunction is integrated.

Specifically, the integration returned an NaN if the integration was
*up to* an NaN (real inegrals are robust); and the results were negative
if integrating from a to b where a > b.
This commit is contained in:
Joel Therrien 2019-07-19 14:14:36 -07:00
parent ae9a6b9a3f
commit 7371dab4f1
2 changed files with 64 additions and 2 deletions

View file

@ -134,7 +134,7 @@ public final class RightContinuousStepFunction extends StepFunction {
} }
if(to < from){ if(to < from){
return integrate(to, from); return -integrate(to, from);
} }
double summation = 0.0; double summation = 0.0;
@ -177,7 +177,7 @@ public final class RightContinuousStepFunction extends StepFunction {
final double currentTime = xPoints[i]; final double currentTime = xPoints[i];
final double currentHeight = evaluateByIndex(i); final double currentHeight = evaluateByIndex(i);
if(i == xPoints.length-1 || xPoints[i+1] > to){ if(i == xPoints.length-1 || xPoints[i+1] >= to){
summation += currentHeight * (to - currentTime); summation += currentHeight * (to - currentTime);
return summation; return summation;
} }

View file

@ -19,6 +19,9 @@ package ca.joeltherrien.randomforest.utils;
import ca.joeltherrien.randomforest.TestUtils; import ca.joeltherrien.randomforest.TestUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class RightContinuousStepFunctionIntegrationTest { public class RightContinuousStepFunctionIntegrationTest {
private RightContinuousStepFunction createTestFunction(){ private RightContinuousStepFunction createTestFunction(){
@ -75,5 +78,64 @@ public class RightContinuousStepFunctionIntegrationTest {
} }
@Test
public void testInvertedFromTo(){
final RightContinuousStepFunction function = createTestFunction();
final double area1 = function.integrate(0, 3.0);
final double area2 = function.integrate(3.0, 0.0);
assertEquals(area1, -area2, 0.0000001);
}
@Test
public void testIntegratingUpToNan(){
// Idea here - you have a function that is valid up to point x where it becomes NaN
// You should be able to integrate *up to* point x and not get an NaN
final RightContinuousStepFunction function1 = new RightContinuousStepFunction(
new double[]{1.0, 2.0, 3.0, 4.0},
new double[]{1.0, 1.0, 1.0, Double.NaN},
0.0);
final double area1 = function1.integrate(0.0, 4.0);
assertEquals(3.0, area1, 0.000000001);
final double nanArea1 = function1.integrate(0.0, 4.0001);
assertTrue(Double.isNaN(nanArea1));
// This tests integrating over the defaultY up to the NaN point
final RightContinuousStepFunction function2 = new RightContinuousStepFunction(
new double[]{1.0, 2.0, 3.0, 4.0},
new double[]{Double.NaN, 1.0, 1.0, Double.NaN},
1.0);
final double area2 = function2.integrate(0.0, 1.0);
assertEquals(1.0, area2, 0.000000001);
final double nanArea2 = function2.integrate(0.0, 4.0);
assertTrue(Double.isNaN(nanArea2));
// This tests integrating between two NaN points. Note that of course for RightContinuousValues carry the previous
// value until the next x point, so this is just making sure the code works if the x-value we pass over is NaN
final RightContinuousStepFunction function3 = new RightContinuousStepFunction(
new double[]{1.0, 2.0, 3.0, 4.0},
new double[]{Double.NaN, 1.0, 1.0, Double.NaN},
0.0);
final double area3 = function3.integrate(2.0, 4.0);
assertEquals(2.0, area3, 0.000000001);
final double nanArea3 = function3.integrate(0.0, 4.0001);
assertTrue(Double.isNaN(nanArea3));
}
} }