/*
* This file is part of JGAP.
*
* JGAP offers a dual license model containing the LGPL as well as the MPL.
*
* For licensing information please see the file license.txt included with JGAP
* or have a look at the top of class org.jgap.Chromosome which representatively
* includes the JGAP license policy applicable for any file delivered with JGAP.
*/
package org.jgap.impl;
import org.jgap.*;
/**
* Base class for all Genes based on numbers.
*
* @author Klaus Meffert
* @since 1.1 (most code moved and adapted from IntegerGene)
*/
public abstract class NumberGene
extends BaseGene {
/** String containing the CVS revision. Read out via reflection!*/
private static final String CVS_REVISION = "$Revision: 1.23 $";
/**
* References the internal value (allele) of this Gene
* E.g., for DoubleGene this is of type Double
*/
private Object m_value;
public NumberGene(Configuration a_config) throws InvalidConfigurationException {
super(a_config);
}
/**
* Compares this NumberGene with the specified object (which must also
* be a NumberGene) for order, which is determined by the number value of
* this Gene compared to the one provided for comparison.
*
* @param a_other the NumberGene to be compared to this NumberGene
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the object provided for comparison
*
* @throws ClassCastException if the specified object's type prevents it
* from being compared to this NumberGene
*
* @author Klaus Meffert
* @since 1.1
*/
public int compareTo(final Object a_other) {
NumberGene otherGene = (NumberGene) a_other;
// First, if the other gene (or its value) is null, then this is
// the greater allele. Otherwise, just use the overridden compareToNative
// method to perform the comparison.
// ----------------------------------------------------------------------
if (otherGene == null) {
return 1;
}
else if (otherGene.m_value == null) {
// Check if type corresponds (because we could have a type not inherited
// from NumberGene).
// ---------------------------------------------------------------------
if (!otherGene.getClass().equals(getClass())) {
throw new ClassCastException(
"Comparison not possible: different types!");
}
// If our value is also null, then we're the same. Otherwise,
// this is the greater gene.
// ----------------------------------------------------------
if (m_value == null) {
if (isCompareApplicationData()) {
return compareApplicationData(getApplicationData(),
otherGene.getApplicationData());
}
else {
return 0;
}
}
else {
return 1;
}
}
else {
try {
if (!otherGene.getClass().equals(getClass())) {
throw new ClassCastException(
"Comparison not possible: different types!");
}
if (m_value == null) {
return -1;
}
int res = compareToNative(m_value, otherGene.m_value);
if (res == 0) {
if (isCompareApplicationData()) {
return compareApplicationData(getApplicationData(),
otherGene.getApplicationData());
}
else {
return 0;
}
}
else {
return res;
}
}
catch (ClassCastException e) {
throw e;
}
}
}
/**
* Compares to objects by first casting them into their expected type
* (e.g. Integer for IntegerGene) and then calling the compareTo-method
* of the casted type.
*
* @param a_o1 first object to be compared, always is not null
* @param a_o2 second object to be compared, always is not null
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the object provided for comparison
*
* @author Klaus Meffert
* @since 1.1
*/
protected abstract int compareToNative(Object a_o1, Object a_o2);
/**
* Sets the value (allele) of this Gene to the new given value. This class
* expects the value to be an instance of current type (e.g. Integer).
* If the value is above or below the upper or lower bounds, it will be
* mappped to within the allowable range.
*
* @param a_newValue the new value of this Gene instance
*
* @author Klaus Meffert
* @since 1.1
*/
public void setAllele(final Object a_newValue) {
if (getConstraintChecker() != null) {
if (!getConstraintChecker().verify(this, a_newValue, null, -1)) {
return;
}
}
m_value = a_newValue;
// If the value isn't between the upper and lower bounds of this
// Gene, map it to a value within those bounds.
// -------------------------------------------------------------
mapValueToWithinBounds();
}
/**
* Maps the value of this NumberGene to within the bounds specified by
* the m_upperBounds and m_lowerBounds instance variables. The value's
* relative position within the integer range will be preserved within the
* bounds range (in other words, if the value is about halfway between the
* integer max and min, then the resulting value will be about halfway
* between the upper bounds and lower bounds). If the value is null or
* is already within the bounds, it will be left unchanged.
*
* @author Klaus Meffert
* @since 1.1
*/
protected abstract void mapValueToWithinBounds();
protected Object getInternalValue() {
return m_value;
}
}