org.drools.verifier.misc.FindMissingNumber Maven / Gradle / Ivy
/*
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.verifier.misc;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import org.drools.verifier.components.NumberRestriction;
public class FindMissingNumber {
public static final int MIN_NUMBER_OF_RESTRICTIONS = 4;
/**
* Test if the values in constraints are in pattern.
*
* @param restrictions
* @return false if can't find a pattern or constraints list is null or size
* of the list is under 3.
*/
public static Number testForPattern(Collection restrictions) {
if ( restrictions == null || restrictions.size() < MIN_NUMBER_OF_RESTRICTIONS ) {
return null;
}
BigDecimal[] numbers = new BigDecimal[restrictions.size()];
int index = 0;
for ( NumberRestriction restriction : restrictions ) {
if ( restriction.isInt() ) {
numbers[index++] = BigDecimal.valueOf( restriction.getValue().intValue() );
} else {
numbers[index++] = BigDecimal.valueOf( restriction.getValue().doubleValue() );
}
}
Arrays.sort( numbers );
Number missingNumber = findSumPattern( numbers );
if ( missingNumber != null ) {
return missingNumber;
} else {
missingNumber = findMultiplicationPattern( numbers );
if ( missingNumber != null ) {
return missingNumber;
}
}
return null;
}
/**
* Looks for sum pattern, on each step x is added or removed. -x is the same
* as +(-x) so this works for both.
*
* @param numbers
* @return true if pattern is found.
*/
protected static Number findSumPattern(BigDecimal[] numbers) {
if ( numbers == null || numbers.length < MIN_NUMBER_OF_RESTRICTIONS ) {
return null;
}
BigDecimal gap = null;
Number missingNumber = null;
BigDecimal a = numbers[0];
BigDecimal b = numbers[1];
BigDecimal c = numbers[2];
BigDecimal d = numbers[3];
// Uses first four numbers to check if there is a pattern and to
// calculate the gap between them. One missing value is allowed.
if ( b.subtract( a ).equals( c.subtract( b ) ) ) {
gap = b.subtract( a );
} else if ( c.subtract( b ).equals( d.subtract( c ) ) ) {
gap = c.subtract( b );
} else if ( b.subtract( a ).equals( d.subtract( c ) ) ) {
gap = b.subtract( a );
} else {
// No pattern found.
return null;
}
for ( int i = 0; i < (numbers.length - 1); i++ ) {
BigDecimal first = numbers[i];
BigDecimal second = numbers[i + 1];
if ( missingNumber == null && !second.subtract( first ).equals( gap ) ) {
missingNumber = second.subtract( gap );
} else if ( !second.subtract( first ).equals( gap ) && missingNumber != null ) {
// Happends if there is no pattern found, or more than 1
// missing number.
return null;
}
}
return missingNumber;
}
/**
* Looks for multiplication pattern, on each step x multiplied or divided.
* *x is the same as *(1/x) so this works for both.
*
* @param numbers
* @return true if pattern is found.
*/
protected static Number findMultiplicationPattern(BigDecimal[] numbers) {
if ( numbers == null || numbers.length < MIN_NUMBER_OF_RESTRICTIONS ) {
return null;
}
try {
BigDecimal gap = null;
Number missingNumber = null;
BigDecimal a = numbers[0];
BigDecimal b = numbers[1];
BigDecimal c = numbers[2];
BigDecimal d = numbers[3];
// Uses first four numbers to check if there is a pattern and to
// calculate the gap between them. One missing value is allowed.
if ( b.divide( a ).equals( c.divide( b ) ) ) {
gap = b.divide( a );
} else if ( c.divide( b ).equals( d.divide( c ) ) ) {
gap = c.divide( b );
} else if ( b.divide( a ).equals( d.divide( c ) ) ) {
gap = b.divide( a );
} else {
// No pattern found.
return null;
}
BigDecimal first = null;
BigDecimal second = null;
for ( int i = 0; i < (numbers.length - 1); i++ ) {
first = numbers[i];
second = numbers[i + 1];
if ( missingNumber == null && !second.divide( first ).equals( gap ) ) {
missingNumber = first.multiply( gap );
} else if ( !second.divide( first ).equals( gap ) && missingNumber != null ) {
// Happends if there is no pattern found, or more than 1
// missing number.
return null;
}
}
return missingNumber;
} catch ( Exception e ) {
return null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy