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 org.jgap.audit;
011:
012: import org.jgap.*;
013: import java.util.*;
014:
015: /**
016: * Gathers statistical data and returns them on request.
017: *
018: * @author Klaus Meffert
019: * @since 2.2
020: */
021: public class Evaluator {
022: /**@todo implement: overall score calculation (out of best/avg. fitness value
023: * etc.)
024: */
025:
026: /** String containing the CVS revision. Read out via reflection!*/
027: private final static String CVS_REVISION = "$Revision: 1.11 $";
028:
029: /**
030: * Each data has its own data container
031: */
032: private Map m_permutationData;
033:
034: /**
035: * Stores the run-numbers (indexes) for all permutations submitted
036: */
037: private Map m_permutationRuns;
038:
039: /**
040: * For processinf without permutation
041: */
042: private KeyedValues2D m_data;
043:
044: private PermutingConfiguration m_permConf;
045:
046: /**
047: * Genotype data per permutation per run
048: */
049: private Map m_genotypeData;
050:
051: /**
052: * Genotype data per permutation (averaged over all runs)
053: */
054: private List m_genotypeDataAvg;
055:
056: public Evaluator(final PermutingConfiguration a_conf) {
057: if (a_conf == null) {
058: throw new IllegalArgumentException(
059: "Configuration must not be null!");
060: }
061: m_permConf = a_conf;
062: m_data = new KeyedValues2D();
063: m_permutationData = new Hashtable();
064: m_permutationRuns = new Hashtable();
065: m_genotypeData = new Hashtable();
066: m_genotypeDataAvg = new Vector();
067: }
068:
069: public boolean hasNext() {
070: return m_permConf.hasNext();
071: }
072:
073: public Configuration next() throws InvalidConfigurationException {
074: return m_permConf.next();
075: }
076:
077: public void setValue(double a_value, Comparable a_rowKey,
078: Comparable a_columnKey) {
079: m_data.setValue(new Double(a_value), a_rowKey, a_columnKey);
080: // fireDatasetChanged();
081: }
082:
083: public Number getValue(Comparable rowKey, Comparable columnKey) {
084: return m_data.getValue(rowKey, columnKey);
085: }
086:
087: /**
088: * Sets a specific value.
089: * @param a_permutation int
090: * @param a_run int
091: * @param a_value double
092: * @param a_rowKey Comparable
093: * @param a_columnKey Comparable
094: *
095: * @author Klaus Meffert
096: * @since 2.2
097: */
098: public void setValue(int a_permutation, int a_run, double a_value,
099: Comparable a_rowKey, Comparable a_columnKey) {
100: Object key = createKey(a_permutation, a_run);
101: KeyedValues2D a_data = (KeyedValues2D) m_permutationData
102: .get(key);
103: if (a_data == null) {
104: a_data = new KeyedValues2D();
105: m_permutationData.put(key, a_data);
106: }
107: // Add run-number (index).
108: // -----------------------
109: addRunNumber(a_permutation, a_run);
110: a_data.setValue(new Double(a_value), a_rowKey, a_columnKey);
111: }
112:
113: protected void addRunNumber(int a_permutation, int a_run) {
114: Map v = (Map) m_permutationRuns.get(new Integer(a_permutation));
115: if (v == null) {
116: v = new Hashtable();
117: }
118: v.put(new Integer(a_run), new Integer(a_run));
119: m_permutationRuns.put(new Integer(a_permutation), v);
120: }
121:
122: public Number getValue(int a_permutation, int a_run,
123: Comparable rowKey, Comparable columnKey) {
124: KeyedValues2D a_data = (KeyedValues2D) m_permutationData
125: .get(createKey(a_permutation, a_run));
126: if (a_data == null) {
127: return null;
128: }
129: return a_data.getValue(rowKey, columnKey);
130: }
131:
132: public KeyedValues2D getData() {
133: return m_data;
134: }
135:
136: protected Object createKey(int a_permutation, int a_run) {
137: return a_permutation + "_" + a_run;
138: }
139:
140: /**
141: * Calculates the average fitness value curve for a given permutation.
142: * If permutation -1 is given, a composition of all permutations available
143: * is created.
144: * @param a_permutation -1 to use all permutations
145: * @return DefaultKeyedValues2D list of fitness values, one for each
146: * individual in the generation
147: *
148: * @author Klaus Meffert
149: * @since 2.2
150: */
151: public KeyedValues2D calcAvgFitness(int a_permutation) {
152: if (a_permutation == -1) {
153: Iterator it = m_permutationRuns.keySet().iterator();
154: Integer permNumberI;
155: int permNumber;
156: KeyedValues2D result = new KeyedValues2D();
157: while (it.hasNext()) {
158: permNumberI = (Integer) it.next();
159: permNumber = permNumberI.intValue();
160: calcAvgFitnessHelper(permNumber, result);
161: }
162: return result;
163: } else {
164: KeyedValues2D a_data = new KeyedValues2D();
165: calcAvgFitnessHelper(a_permutation, a_data);
166: return a_data;
167: }
168: }
169:
170: protected void calcAvgFitnessHelper(int a_permutation,
171: final KeyedValues2D result) {
172: // Determine run-numbers of given permutation.
173: // -------------------------------------------
174: Map runNumbers = (Map) m_permutationRuns.get(new Integer(
175: a_permutation));
176: if (runNumbers == null) {
177: return;
178: }
179: // Loop over all run-numbers.
180: // --------------------------
181: Iterator it = runNumbers.keySet().iterator();
182: int numRuns = runNumbers.keySet().size();
183: Integer runI;
184: while (it.hasNext()) {
185: runI = (Integer) it.next();
186: // Determine dataset of given permutation.
187: // ---------------------------------------
188: KeyedValues2D a_data = (KeyedValues2D) m_permutationData
189: .get(createKey(a_permutation, runI.intValue()));
190: // Determine values for current run-number and "add" them to gathered
191: // data.
192: // ------------------------------------------------------------------
193: for (int col = 0; col < a_data.getColumnCount(); col++) {
194: for (int row = 0; row < a_data.getRowCount(); row++) {
195: // Previous value (summation).
196: // --------------------------.
197: Double d = (Double) result.getValue(a_data
198: .getRowKey(row), a_data.getColumnKey(col));
199: double newValue;
200: if (d == null) {
201: newValue = 0.0d;
202: } else {
203: newValue = d.doubleValue();
204: }
205: // Add current value (divided by total number of runs to get an
206: // averaged value).
207: // ------------------------------------------------------------
208: newValue += a_data.getValue(a_data.getRowKey(row),
209: a_data.getColumnKey(col)).doubleValue()
210: / numRuns;
211: // Set averaged value back to result dataset.
212: // ------------------------------------------
213: result.setValue(new Double(newValue), a_data
214: .getRowKey(row), a_data.getColumnKey(col));
215: }
216: }
217: }
218: }
219:
220: /**
221: * Returns a list of lists (i.e. a matrix) to use for output as a table
222: * @param a_data DefaultKeyedValues2D
223: * @return List
224: */
225: /**@todo implement*/
226: // public List getTable(KeyedValues2D a_data) {
227: // return null;
228: // }
229: /**
230: * Calculates average fitness value improvement per generation.
231: *
232: * @param a_permutation int
233: * @return DefaultKeyedValues2D
234: *
235: * @author Klaus Meffert
236: * @since 2.2
237: */
238: public KeyedValues2D calcAvgFitnessImpr(int a_permutation) {
239: /**@todo implement*/
240: /**@todo is this method used resp. contained in calcPerformance?*/
241: Map runNumbers = (Map) m_permutationRuns.get(new Integer(
242: a_permutation));
243: if (runNumbers == null) {
244: return null;
245: }
246: // Map fitnessImpr = new Hashtable();
247: // Loop over all run-numbers.
248: // --------------------------
249: Iterator it = runNumbers.keySet().iterator();
250: // int numRuns = runNumbers.keySet().size();
251: Integer runI;
252: while (it.hasNext()) {
253: runI = (Integer) it.next();
254: // Determine dataset of given permutation.
255: // ---------------------------------------
256: KeyedValues2D a_data = (KeyedValues2D) m_permutationData
257: .get(createKey(a_permutation, runI.intValue()));
258: for (int col = 0; col < a_data.getColumnCount(); col++) {
259: for (int row = 0; row < a_data.getRowCount(); row++) {
260: }
261: }
262: }
263: return null;
264: }
265:
266: /**
267: *
268: * @param a_permutation the permutation to determine the number of runs for
269: * @return the number of runs for the given permutation
270: */
271: public int getNumberOfRuns(int a_permutation) {
272: Map runNumbers = (Map) m_permutationRuns.get(new Integer(
273: a_permutation));
274: if (runNumbers == null) {
275: return 0;
276: } else {
277: return runNumbers.keySet().size();
278: }
279: }
280:
281: /**
282: * Stores information contained in the given genotype.
283: * @param a_permutation int
284: * @param a_run index of the run proceeded for the given genotype
285: * @param a_genotype the genotype holding the population of chromosomes
286: *
287: * @author Klaus Meffert
288: * @since 2.2
289: */
290: public void storeGenotype(int a_permutation, int a_run,
291: Genotype a_genotype) {
292: /**@todo implement*/
293: // average and maximum fitness value
294: //
295: GenotypeData data = new GenotypeData();
296: int generation = a_genotype.getConfiguration()
297: .getGenerationNr();
298: data.generation = generation;
299: Population pop = a_genotype.getPopulation();
300: data.hashCode = a_genotype.hashCode();
301: int popSize = pop.size();
302: data.chromosomeData = new ChromosomeData[popSize];
303: data.size = popSize;
304: // gather data of Chromosomes
305: IChromosome chrom;
306: ChromosomeData chromData;
307: for (int i = 0; i < popSize; i++) {
308: chrom = pop.getChromosome(i);
309: chromData = new ChromosomeData();
310: chromData.fitnessValue = chrom.getFitnessValue();
311: chromData.size = chrom.size();
312: chromData.index = i;
313: data.chromosomeData[i] = chromData;
314: }
315: String key = a_permutation + "_" + a_run;
316: m_genotypeData.put(key, data);
317: addRunNumber(a_permutation, a_run);
318: }
319:
320: public GenotypeData retrieveGenotype(int a_permutation, int a_run) {
321: return (GenotypeData) m_genotypeData.get(a_permutation + "_"
322: + a_run);
323: }
324:
325: /**
326: * Calculates performance metrics for a given permutation and run stored
327: * before with storeGenotype, like:
328: * average fitness, maximum fitness...
329: * @param a_permutation the permutation to compute the performance metrics
330: * for
331: * @return computed statistical data
332: *
333: * @author Klaus Meffert
334: * @since 2.2
335: */
336: public GenotypeDataAvg calcPerformance(int a_permutation) {
337: int numRuns = getNumberOfRuns(a_permutation);
338: GenotypeData data;
339: GenotypeDataAvg dataAvg = new GenotypeDataAvg();
340: dataAvg.permutation = a_permutation;
341: double sizeAvg = 0.0d;
342: double fitnessAvg = 0.0d;
343: double fitnessBest = -1.0d;
344: double fitnessBestOld = -1.0d;
345: double fitness;
346: int fitnessBestGen = -1;
347: double fitnessAvgChroms;
348: double fitnessDiversityChromsOld = -1.0d;
349: double fitnessBestDeltaAvg = 0.0d;
350: double fitnessDiversity;
351: double fitnessDiversityAvg = 0.0d;
352: int size;
353: ChromosomeData chrom;
354: for (int i = 0; i < numRuns; i++) {
355: data = retrieveGenotype(a_permutation, i);
356: // generation the genotype data represents
357: if (i == 0) {
358: dataAvg.generation = data.generation;
359: }
360: // average number of chromosomes
361: sizeAvg += (double) data.size / numRuns;
362: size = data.size;
363: fitnessAvgChroms = 0.0d;
364: fitnessDiversity = 0.0d;
365: double fitnessBestLocal = -1.0d;
366: for (int j = 0; j < size; j++) {
367: chrom = data.chromosomeData[j];
368: fitness = chrom.fitnessValue;
369: // diversity of fitness values over all chromosomes
370: if (j > 0) {
371: fitnessDiversity += Math.abs(fitness
372: - fitnessDiversityChromsOld)
373: / (size - 1);
374: }
375: fitnessDiversityChromsOld = fitness;
376: // average fitness value for generation over all Chromosomes
377: fitnessAvgChroms += fitness / size;
378: // fittest chromosome in generation over all runs
379: if (fitnessBest < fitness) {
380: fitnessBest = fitness;
381: // memorize generation number in which fittest chromosome appeared
382: fitnessBestGen = data.generation;
383: }
384: // fittest chromosome in generation over current runs
385: if (fitnessBestLocal < fitness) {
386: fitnessBestLocal = fitness;
387: }
388: }
389: // average fitness value for generation over all runs
390: fitnessAvg += fitnessAvgChroms / numRuns;
391: // average fitness delta value for generation over all runs
392: fitnessDiversityAvg += fitnessDiversity / numRuns;
393: // absolute delta between two adjacent best fitness values
394: if (i > 0) {
395: fitnessBestDeltaAvg += Math.abs(fitnessBestLocal
396: - fitnessBestOld)
397: / (numRuns - 1);
398: }
399: fitnessBestOld = fitnessBestLocal;
400: }
401: dataAvg.sizeAvg = sizeAvg;
402: dataAvg.avgFitnessValue = fitnessAvg;
403: dataAvg.bestFitnessValue = fitnessBest;
404: dataAvg.bestFitnessValueGeneration = fitnessBestGen;
405: dataAvg.avgDiversityFitnessValue = fitnessDiversityAvg;
406: dataAvg.avgBestDeltaFitnessValue = fitnessBestDeltaAvg;
407: //store computed (averaged) data
408: m_genotypeDataAvg.add(dataAvg);
409: return dataAvg;
410: }
411:
412: /**
413: * Averaged genotype data (computed over all runs of a permutation)
414: *
415: * @author Klaus Meffert
416: * @since 2.2
417: */
418: public class GenotypeDataAvg {
419: public int permutation;
420:
421: public int generation;
422:
423: public double sizeAvg;
424:
425: public double bestFitnessValue;
426:
427: public double avgFitnessValue;
428:
429: public int bestFitnessValueGeneration;
430:
431: public double avgDiversityFitnessValue;
432:
433: public double avgBestDeltaFitnessValue;
434: }
435:
436: /**
437: * Genotype data for one single run
438: *
439: * @author Klaus Meffert
440: * @since 2.2
441: */
442: public class GenotypeData {
443: public int generation;
444:
445: public int hashCode;
446:
447: public int size;
448:
449: public ChromosomeData[] chromosomeData;
450: }
451:
452: public class ChromosomeData {
453: public int index;
454:
455: public int size;
456:
457: public double fitnessValue;
458: }
459: }
|