JIRA: MATH-675 Added isMonotone methods to MathUtils and cleaned up checkOrder.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1173974 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Greg Sterijevski 2011-09-22 07:34:05 +00:00
parent 041df9cd9b
commit cc40bb40a9
3 changed files with 165 additions and 18 deletions

View File

@ -1949,6 +1949,100 @@ public final class MathUtils {
/** Constant for decreasing direction. */
DECREASING
}
/**
* Check that an array is monotone increasing or decreasing
*
* @param val Values.
* @param dir Ordering direction.
* @param strict Whether the order should be strict.
* @return {@code true} if sorted, {@code false} otherwise
*/
public static boolean isMonotone(Comparable[] val, OrderDirection dir,
boolean strict){
Comparable previous = val[0];
int max = val.length;
int comp;
for (int i = 1; i < max; i++) {
switch (dir) {
case INCREASING:
comp = -val[i].compareTo(previous);
if (strict) {
if (0 <= comp) {
return false;
}
} else {
if ( comp > 0) {
return false;
}
}
break;
case DECREASING:
comp = val[i].compareTo(previous);
if (strict) {
if (comp >= 0) {
return false;
}
} else {
if (comp > 0) {
return false;
}
}
break;
default:
// Should never happen.
throw new IllegalArgumentException();
}
previous = val[i];
}
return true;
}
/**
* Check that an array is monotone increasing or decreasing
*
* @param val Values.
* @param dir Ordering direction.
* @param strict Whether the order should be strict.
* @return {@code true} if sorted, {@code false} otherwise
*/
public static boolean isMonotone( double[] val, OrderDirection dir,
boolean strict){
double previous = val[0];
int max = val.length;
for (int i = 1; i < max; i++) {
switch (dir) {
case INCREASING:
if (strict) {
if (val[i] <= previous) {
return false;
}
} else {
if (val[i] < previous) {
return false;
}
}
break;
case DECREASING:
if (strict) {
if (val[i] >= previous) {
return false;
}
} else {
if (val[i] > previous) {
return false;
}
}
break;
default:
// Should never happen.
throw new IllegalArgumentException();
}
previous = val[i];
}
return true;
}
/**
* Check that the given array is sorted.
@ -1964,30 +2058,40 @@ public final class MathUtils {
public static boolean checkOrder(double[] val, OrderDirection dir,
boolean strict, boolean abort) {
double previous = val[0];
boolean ok = true;
int max = val.length;
for (int i = 1; i < max; i++) {
switch (dir) {
case INCREASING:
if (strict) {
if (val[i] <= previous) {
ok = false;
if (abort) {
throw new NonMonotonousSequenceException((Number)val[i], (Number)previous, i, dir, strict);
}
return false;
}
} else {
if (val[i] < previous) {
ok = false;
if (abort) {
throw new NonMonotonousSequenceException((Number)val[i], (Number)previous, i, dir, strict);
}
return false;
}
}
break;
case DECREASING:
if (strict) {
if (val[i] >= previous) {
ok = false;
if (abort) {
throw new NonMonotonousSequenceException((Number)val[i], (Number)previous, i, dir, strict);
}
return false;
}
} else {
if (val[i] > previous) {
ok = false;
if (abort) {
throw new NonMonotonousSequenceException((Number)val[i], (Number)previous, i, dir, strict);
}
return false;
}
}
break;
@ -1995,15 +2099,9 @@ public final class MathUtils {
// Should never happen.
throw new IllegalArgumentException();
}
if (!ok &&
abort) {
throw new NonMonotonousSequenceException(val[i], previous, i, dir, strict);
}
previous = val[i];
}
return ok;
return true;
}
/**

View File

@ -52,6 +52,9 @@ The <action> type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces!
-->
<release version="3.0" date="TBD" description="TBD">
<action dev="gregs" type="update" issue="MATH-675">
Added isMonotone methods in MathUtils. Optimized checkOrder method.
</action>
<action dev="erans" type="fix" issue="MATH-664">
In class "AbstractLeastSquaresOptimizer": Allow to specify a singularity
threshold in call to "getCovariances" method.

View File

@ -1087,7 +1087,7 @@ public final class MathUtilsTest {
Assert.assertEquals(expected,
MathUtils.reduce(orig, -period, offset),
1e-6);
Assert.assertTrue(Double.isNaN(MathUtils.reduce(orig, Double.NaN, offset)));
Assert.assertTrue(Double.isNaN(MathUtils.reduce(Double.NaN, period, offset)));
Assert.assertTrue(Double.isNaN(MathUtils.reduce(orig, period, Double.NaN)));
@ -1096,13 +1096,13 @@ public final class MathUtilsTest {
Assert.assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
period, offset)));
Assert.assertTrue(Double.isNaN(MathUtils.reduce(orig,
Double.POSITIVE_INFINITY, offset)));
Double.POSITIVE_INFINITY, offset)));
Assert.assertTrue(Double.isNaN(MathUtils.reduce(orig,
Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)));
Assert.assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
period, Double.POSITIVE_INFINITY)));
Assert.assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY, offset)));
Double.POSITIVE_INFINITY, offset)));
Assert.assertTrue(Double.isNaN(MathUtils.reduce(Double.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)));
}
@ -1251,7 +1251,7 @@ public final class MathUtilsTest {
try {
MathUtils.round(1.234, 2, BigDecimal.ROUND_UNNECESSARY);
Assert.fail();
} catch (ArithmeticException ex) {
} catch (ArithmeticException ex) {
// expected
}
@ -1650,6 +1650,52 @@ public final class MathUtilsTest {
}
}
@Test
public void testIsMonotone() {
if(MathUtils.isMonotone(new double[] {-15, -5.5, -1, -1, 2,15},
MathUtils.OrderDirection.INCREASING, true) ){
Assert.fail("an exception should have been thrown");
}
if(MathUtils.isMonotone(new double[] {-15, -5.5,-1,-2,2},
MathUtils.OrderDirection.INCREASING, false)){
Assert.fail("an exception should have been thrown");
}
if(MathUtils.isMonotone(new double[] {3,3,-5.5,-11,-27.5},
MathUtils.OrderDirection.DECREASING, true)){
Assert.fail("an exception should have been thrown");
}
if( MathUtils.isMonotone(new double[] {3,-1,0,-5.5,-11,-27.5},
MathUtils.OrderDirection.DECREASING, false) ){
Assert.fail("an exception should have been thrown");
}
}
@Test
public void testIsMonotoneComparable() {
if(MathUtils.isMonotone(new Double[] {new Double(-15), new Double(-5.5), new Double(-1), new Double(-1), new Double(2), new Double(15)},
MathUtils.OrderDirection.INCREASING, true) ){
Assert.fail("an exception should have been thrown");
}
if(MathUtils.isMonotone(new Double[] {new Double(-15), new Double(-5.5), new Double(-1), new Double(-2), new Double(2)},
MathUtils.OrderDirection.INCREASING, false)){
Assert.fail("an exception should have been thrown");
}
if(MathUtils.isMonotone(new Double[] {new Double(3), new Double(3), new Double(-5.5), new Double(-11), new Double(-27.5)},
MathUtils.OrderDirection.DECREASING, true)){
Assert.fail("an exception should have been thrown");
}
if( MathUtils.isMonotone(new Double[] {new Double(3), new Double(-1), new Double(0), new Double(-5.5), new Double(-11), new Double(-27.5)},
MathUtils.OrderDirection.DECREASING, false) ){
Assert.fail("an exception should have been thrown");
}
}
@Test
public void testCheckFinite() {
try {
@ -1696,7 +1742,7 @@ public final class MathUtilsTest {
final double[] x1 = {2, 5, -3, 1, 4};
final double[] x2 = {4, 25, 9, 1, 16};
final double[] x3 = {8, 125, -27, 1, 64};
MathUtils.sortInPlace(x1, x2, x3);
Assert.assertEquals(-3, x1[0], Math.ulp(1d));