001: /*
002: * This file is part of JGAP.
003: *
004: * JGAP offers a dual license model containing the LGPL as well as the MPL.
005: *
006: * For licensing information please see the file license.txt included with JGAP
007: * or have a look at the top of class org.jgap.Chromosome which representatively
008: * includes the JGAP license policy applicable for any file delivered with JGAP.
009: */
010: package examples.supergene;
011:
012: import org.jgap.*;
013: import org.jgap.impl.*;
014: import examples.super gene.*;
015:
016: /**
017: * Sample fitness function for the MakeChange example, including supergenes.
018: *
019: * @author Neil Rotstan
020: * @author Klaus Meffert
021: * @author Audrius Meskauskas
022: * @since 2.0
023: */
024: public abstract class AbstractChangeFitnessFunction extends
025: FitnessFunction {
026: /** String containing the CVS revision. Read out via reflection!*/
027: private final static String CVS_REVISION = "$Revision: 1.2 $";
028:
029: private final int m_targetAmount;
030:
031: public AbstractChangeFitnessFunction(int a_targetAmount) {
032: if (a_targetAmount < 1 || a_targetAmount > 99) {
033: throw new IllegalArgumentException(
034: "Change amount must be between 1 and 99 cents.");
035: }
036: m_targetAmount = a_targetAmount;
037: }
038:
039: /**
040: * Determine the fitness of the given Chromosome instance. The higher the
041: * return value, the more fit the instance. This method should always
042: * return the same fitness value for two equivalent Chromosome instances.
043: *
044: * @param a_subject the Chromosome instance to evaluate
045: *
046: * @return positive integer reflecting the fitness rating of the given
047: * Chromosome
048: * @since 2.0
049: */
050: public double evaluate(IChromosome a_subject) {
051: // The fitness value measures both how close the value is to the
052: // target amount supplied by the user and the total number of coins
053: // represented by the solution. We do this in two steps: first,
054: // we consider only the represented amount of change vs. the target
055: // amount of change and return higher fitness values for amounts
056: // closer to the target, and lower fitness values for amounts further
057: // away from the target. If the amount equals the target, then we go
058: // to step 2, which returns a higher fitness value for solutions
059: // representing fewer total coins, and lower fitness values for
060: // solutions representing more total coins.
061: // ------------------------------------------------------------------
062: int changeAmount = amountOfChange(a_subject);
063: int totalCoins = getTotalNumberOfCoins(a_subject);
064: int changeDifference = Math.abs(m_targetAmount - changeAmount);
065: // Step 1: Determine distance of amount represented by solution from
066: // the target amount. Since we know the maximum amount of change is
067: // 99 cents, we'll subtract the difference in change between the
068: // solution amount and the target amount from 99. That will give
069: // the desired effect of returning higher values for amounts
070: // closer to the target amount and lower values for amounts
071: // further away from the target amount.
072: // -----------------------------------------------------------------
073: int fitness = (99 - changeDifference);
074: // Step 2: If the solution amount equals the target amount, then
075: // we add additional fitness points for solutions representing fewer
076: // total coins.
077: // -----------------------------------------------------------------
078: if (changeAmount == m_targetAmount) {
079: // was fitness += 100 - (10 * totalCoins);
080: // The function should be more tolearant to the large amount of coins:
081: // -------------------------------------------------------------------
082: fitness += 100 - totalCoins;
083: }
084: // Make sure fitness value is always positive.
085: // -------------------------------------------
086: return Math.max(1, fitness);
087: }
088:
089: /**
090: * Calculates the total amount of change (in cents) represented by
091: * the given potential solution and returns that amount.
092: *
093: * @param a_potentialSolution the potential solution to evaluate
094: * @return the total amount of change (in cents) represented by the
095: * given solution
096: */
097: public int amountOfChange(IChromosome a_potentialSolution) {
098: int numQuarters = getNumberOfCoinsAtGene(a_potentialSolution,
099: SupergeneSample.QUARTERS);
100: int numDimes = getNumberOfCoinsAtGene(a_potentialSolution,
101: SupergeneSample.DIMES);
102: int numNickels = getNumberOfCoinsAtGene(a_potentialSolution,
103: SupergeneSample.NICKELS);
104: int numPennies = getNumberOfCoinsAtGene(a_potentialSolution,
105: SupergeneSample.PENNIES);
106: return AbstractSupergeneTest.amountOfChange(numQuarters,
107: numDimes, numNickels, numPennies);
108: }
109:
110: /**
111: * Retrieves the number of coins represented by the given potential
112: * solution at the given gene position.
113: *
114: * @param a_potentialSolution the potential solution to evaluate
115: * @param a_code index of gene
116: * @return the number of coins represented by the potential solution
117: * at the given gene position
118: */
119: public int getNumberOfCoinsAtGene(IChromosome a_potentialSolution,
120: int a_code) {
121: Gene g = getResponsibleGene(a_potentialSolution, a_code);
122: return ((IntegerGene) g).intValue();
123: }
124:
125: /**
126: * Returns the total number of coins represented by all of the genes in
127: * the given potential solution.
128: *
129: * @param a_potentialsolution the potential solution to evaluate
130: * @return the total number of coins represented by the given Chromosome
131: */
132: public int getTotalNumberOfCoins(IChromosome a_potentialsolution) {
133: return getNumberOfCoinsAtGene(a_potentialsolution,
134: SupergeneSample.QUARTERS)
135: + getNumberOfCoinsAtGene(a_potentialsolution,
136: SupergeneSample.DIMES)
137: + getNumberOfCoinsAtGene(a_potentialsolution,
138: SupergeneSample.NICKELS)
139: + getNumberOfCoinsAtGene(a_potentialsolution,
140: SupergeneSample.PENNIES);
141: }
142:
143: /**
144: * Get the gene, responsible for the number of coins, corresponding
145: * this code.
146: *
147: * @param a_chromosome Chromosome to evaluate
148: * @param a_code index of Gene
149: * @return responsible gene
150: */
151: public abstract Gene getResponsibleGene(IChromosome a_chromosome,
152: int a_code);
153: }
|