package Sequenic.T2ext.CoverageEngine.ga; import java.lang.reflect.Method; import java.util.LinkedList; import java.util.Random; import org.uncommons.maths.random.MersenneTwisterRNG; import org.uncommons.watchmaker.framework.CandidateFactory; import org.uncommons.watchmaker.framework.EvolutionEngine; import org.uncommons.watchmaker.framework.EvolutionObserver; import org.uncommons.watchmaker.framework.EvolutionaryOperator; import org.uncommons.watchmaker.framework.PopulationData; import org.uncommons.watchmaker.framework.SelectionStrategy; import org.uncommons.watchmaker.framework.SequentialEvolutionEngine; import org.uncommons.watchmaker.framework.selection.RouletteWheelSelection; import org.uncommons.watchmaker.framework.termination.Stagnation; import org.uncommons.watchmaker.framework.termination.TargetFitness; import Sequenic.T2.Seq.CALL_METHOD; import Sequenic.T2.Seq.REF; import Sequenic.T2.Seq.Trace; import Sequenic.T2.Seq.TraceStep; import Sequenic.T2ext.Analyzer.Pair; import Sequenic.T2ext.Analyzer.T2TraceFileCoverageAnalyzer; import Sequenic.T2ext.Analyzer.T2TraceFileCoverageResult; import Sequenic.T2ext.CoverageEngine.BaseEngine; import Sequenic.T2ext.Instrumenter.Node; /** * This engine searches for various patterns that it can solve using a genetic * algorithm. If such a pattern is found it will run the GA to generate new * traces. * * @author Christiaan Hees */ public class GAEngine extends BaseEngine { private String[] t2Args; public GAEngine(T2TraceFileCoverageResult covResult, T2TraceFileCoverageAnalyzer covAnalyzer, LinkedList targetPath, String[] t2Args) { super(covResult, covAnalyzer, targetPath); this.t2Args = t2Args; } @Override public LinkedList> generateTraces() { // TODO // 1. Search for a i1 + i2 == i3 pattern using BCEL // 2. Run the GA // 3. If the GA came with a solution, add it to the traces list and return it // // Things we need for the GA: // 1. We need a CandidateFactory that can produce random traces // 2. Operators that can add, remove or change steps from the traces // 3. A FitnessEvaluator that can determine the fitness of a trace. // It needs to execute the steps in the trace and determine the // distance between i1+i2 and i3 long startTime = System.currentTimeMillis(); CandidateFactory candidateFactory = new TraceFactory(covReport.trfile.traces); //EvolutionaryOperator evolutionScheme = new TraceMutation(t2covAnalyzer.getC()); EvolutionaryOperator evolutionScheme = new TraceMutation(t2Args); // Select a fitness evaluator: Evaluator[] possibleEvaluators = { new CustomEvaluator(this), new IntEqualsIntEvaluator(this), new IntIntEqualsIntEvaluator(this) }; Evaluator fitnessEvaluator = null; for(Evaluator e : possibleEvaluators) { if(e.containingMethod != null) { fitnessEvaluator = e; System.out.println("Using GA evaluator "+e.getClass().getName()); break; } } if(fitnessEvaluator == null) { System.out.println("No solvable GA patterns found."); return null; } SelectionStrategy selectionStrategy = new RouletteWheelSelection(); Random rng = new MersenneTwisterRNG(); EvolutionEngine engine = new SequentialEvolutionEngine( candidateFactory, evolutionScheme, fitnessEvaluator, selectionStrategy, rng); EvolutionLogger evolutionLogger = new EvolutionLogger(); engine.addEvolutionObserver(evolutionLogger); // Run the GA: Trace bestTrace = engine.evolve( 25, // Population size 10, // Elite count new Stagnation(100, fitnessEvaluator.isNatural()), new TargetFitness(0, fitnessEvaluator.isNatural()) //new ElapsedTime(30*1000) ); System.out.println("The best found trace is: "); for(TraceStep ts : bestTrace.trace) { System.out.println(ts); } System.out.println("The fitness of that trace is: "+evolutionLogger.bestFitness); System.out.println("The length of that trace is: "+bestTrace.trace.size()); LinkedList> traces = new LinkedList>(); if(evolutionLogger.bestFitness == 0) { // Make sure the method that needs coverage is at the end: // TODO make it also work on methods with arguments String methodName = fitnessEvaluator.getContainingMethod(); if(!bestTrace.trace.getLast().getName().equals(methodName)) { System.out.println("Adding an extra call to "+methodName+" to the trace."); Method method = null; try { method = t2covAnalyzer.getC().getMethod(methodName, null); } catch (Exception e) { e.printStackTrace(); } bestTrace.trace.add(new CALL_METHOD(method, new REF(0), null)); } traces.add(new Pair(bestTrace, 0)); System.out.println("Covering trace found!"); } else { System.out.println("No covering trace found."); } System.out.println("GA search took "+(System.currentTimeMillis()-startTime)+"ms."); newTraces = traces; return traces; } private static class EvolutionLogger implements EvolutionObserver { private double bestFitness = Integer.MAX_VALUE; public void populationUpdate(PopulationData data) { bestFitness = data.getBestCandidateFitness(); System.out.println("Generation " + data.getGenerationNumber() + ": " + bestFitness); } } }