/******************************************************************** * * Copyright (c) 2006-2007 Berlin Brown and botnode.com All Rights Reserved * * http://www.opensource.org/licenses/bsd-license.php * All rights reserved. * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the Botnode.com (Berlin Brown) nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Date: * Main Description: * Contact: Berlin Brown <berlin dot brown at gmail.com> *********************************************************************/ package org.adder; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * Using Genetic Algorithms to Design Logic Circuits in Java. * * @author bbrown * */ public class EquationGenome extends Genome { /* * Based on * http://www.c-sharpcorner.com/UploadFile/mgold/GAAdderDesign09242005053429AM * /GAAdderDesign.aspx\ * * "Using Genetic Algorithms to Design Logic Circuits in C# By Mike Gold February 05, 2003" */ /** * Number of Symbols */ public static final int NumSymbols = 4; /** * Number of Functions */ public static final int NumFunctions = 4; /** * The Random Seem. */ public static final Random TheSeed = new Random(System.currentTimeMillis()); /** * Calculation Array as a String. */ public static final String[] CalculationStringArray = new String[Population.kLength]; /** * Calculation Array. */ public static final byte[] CalculationArray = new byte[Population.kLength]; /** * The min. */ private int theMin = 0; /** * The max. */ private int theMax = 6; public boolean trialFitness; private List<Gene> theArray = new ArrayList<Gene>(); final byte measure[][] = new byte[][] { { 0, 0, 0, 0, 0, 0, 0, 0 }, // ROW 0 { 0, 0, 0, 1, 0, 0, 0, 1 }, // ROW 1 { 0, 0, 1, 0, 0, 0, 1, 0 }, // ROW 2 { 0, 0, 1, 1, 0, 0, 1, 1 }, // ROW 3 { 0, 1, 0, 0, 0, 0, 0, 1 }, // ROW 4 { 0, 1, 0, 1, 0, 0, 1, 0 }, // ROW 5 { 0, 1, 1, 0, 0, 0, 1, 1 }, // ROW 6 { 0, 1, 1, 1, 0, 1, 0, 0 }, // ROW 7 { 1, 0, 0, 0, 0, 0, 1, 0 }, // ROW 8 { 1, 0, 0, 1, 0, 0, 1, 1 }, // ROW 9 { 1, 0, 1, 0, 0, 1, 0, 0 }, // ROW 10 { 1, 0, 1, 1, 0, 1, 0, 1 }, // ROW 11 { 1, 1, 0, 0, 0, 0, 1, 1 }, // ROW 12 { 1, 1, 0, 1, 0, 1, 0, 0 }, // ROW 13 { 1, 1, 1, 0, 0, 1, 0, 1 }, // ROW 14 { 1, 1, 1, 1, 0, 1, 1, 0 } // ROW 15 }; public static class Gene { /** * */ public int instruction1; /** * */ public int instruction2; /** * */ public int operation; }; /** * Compare to. */ public int compareTo(final Object a) { final EquationGenome gene1 = this; final EquationGenome gene2 = (EquationGenome) a; final Double gened1 = new Double(gene1.currentFitness); final Double gened2 = new Double(gene2.currentFitness); return gened1.compareTo(gened2); } /** * Set the cross over point. */ public void setCrossoverPoint(int crossoverPoint) { this.crossoverPoint = crossoverPoint; } /** * Genome constructor. */ public EquationGenome() { ; } /** * Genome constructor. * * @param length * @param min * @param max */ public EquationGenome(long length, final int min, final int max) { this.length = length; theMin = (int) min; theMax = (int) max; for (int i = 0; i < length; i++) { final Gene nextValue = (Gene) generateGeneValue(min, max, i); theArray.add(nextValue); } } public void initialize() { ; } public boolean canDie(double fitness) { if (currentFitness <= (fitness * 100.0f)) { return true; } return false; } public boolean canReproduce(double fitness) { final double nint = (double) EquationGenome.TheSeed.nextInt(100); if (nint >= fitness * 100.0f) { return true; } return false; } public static final int nextInt(final Random r, final int min, final int max) { final int diff = max - min; final int n = r.nextInt(diff); return n + min; } public Object generateGeneValue(final int min, final int max, final int position) { final Gene g = new Gene(); int nextSeed = 0; nextSeed = nextInt(TheSeed, (int) min, (int) max); g.operation = nextSeed; if (position == 0) { // Generate 0 or 1 for a g.operation = nextInt(TheSeed, 0, NumSymbols); return g; } if (nextSeed > 1) { nextSeed = nextInt(TheSeed, (int) min, position); g.instruction1 = nextSeed; nextSeed = nextInt(TheSeed, (int) min, position); g.instruction2 = nextSeed; } return g; } public void mutate() { int AffectedGenes = TheSeed.nextInt((int) 3); for (int i = 0; i < AffectedGenes; i++) { mutationIndex = nextInt(TheSeed, 0, (int) length); final Gene gene = (Gene) this.generateGeneValue(theMin, theMax, mutationIndex); theArray.set(mutationIndex, gene); } } public String getOperationString(final int operation) { String result = ""; switch (operation) { case 4: // * result = "&"; break; case 5: // / result = "|"; break; case 6: // + result = "^"; break; case 7: // - result = "~"; break; default: // + break; } // end switch System.out.println("@@ GetOperationString =>" + result + " " + operation); return result; } public byte doOperation(final byte a, final byte b, final int operation) { byte result = 0; switch (operation) { case 4: // and result = (byte) (a & b & 1); break; case 5: // or result = (byte) ((a | b) & 1); break; case 6: // xor result = (byte) ((a ^ b) & 1); break; case 7: // - result = (byte) ((~a) & 1); break; default: // + break; }; // end switch //System.out.println("@@ DoOperation =>" + result + " a=" + a + " b=" + b + " c=" + operation); return result; } public String formStepsString() { String _result = "\n"; int count = 0; for (Gene g : theArray) { if (g.operation < NumSymbols) { // a or b, assign value if (g.operation == 0) { _result += count + ": " + "a\n"; } else { _result += count + ": " + "b\n"; } } else if (g.operation == 8) { _result += count + ": " + "PI\n"; } else { // operation, use it to fill calculation in array _result += count + ": " + getOperationString(g.operation) + " " + g.instruction1 + ", " + g.instruction2 + "\n"; } count++; } _result += "\n\n"; return _result; } public String formEquationString() { String _result = ""; int count = 0; for (Gene g : theArray) { if (g.operation < NumSymbols) { // a or b, assign value switch (g.operation) { case 0: CalculationStringArray[count] = "a"; break; case 1: CalculationStringArray[count] = "b"; break; case 2: CalculationStringArray[count] = "c"; break; case 3: CalculationStringArray[count] = "d"; break; } } else if (g.operation == 8) { CalculationStringArray[count] = "1"; } else if (g.operation == 7) { CalculationStringArray[count] = "(" + CalculationStringArray[g.instruction1] + getOperationString(g.operation) + ")"; } else if (g.operation == 9) { // unary CalculationStringArray[count] = "(" + getOperationString(g.operation) + CalculationStringArray[g.instruction1] + ")" + ")"; } else { // operation, use it to fill calculation in array CalculationStringArray[count] = "(" + CalculationStringArray[g.instruction1] + getOperationString(g.operation) + CalculationStringArray[g.instruction2] + ")"; } count++; } _result = CalculationStringArray[Population.kLength - 1]; return _result; } public byte performCalculation(byte a, byte b, byte c, byte d) { int count = 0; for (Gene g : theArray) { if (g.operation < NumSymbols) { // a or b, assign value switch (g.operation) { case 0: CalculationArray[count] = a; break; case 1: CalculationArray[count] = b; break; case 2: CalculationArray[count] = c; break; case 3: CalculationArray[count] = d; break; } ; } else { // operation, use it to fill calculation in array CalculationArray[count] = doOperation(CalculationArray[g.instruction1], CalculationArray[g.instruction2], g.operation); } // End of if - else //System.out.println(" $$ Count =>" + count + " Array => " + CalculationArray[count]); count++; } // End of For Each return CalculationArray[theArray.size() - 1]; // return last calculation } public double calculateFullAdder() { // use the node to calculate the fitness double calc = 0.0f; double sum = 0.0f; int count = measure[0].length; for (int i = 0; i < count; i++) { calc = performCalculation(measure[i][0], measure[i][1], measure[i][2], measure[i][3]); //System.out.println("###-->" + measure[i][measure[1].length - 1]); //System.out.println("### (2) -->" + Math.abs(measure[i][measure[1].length - 1] - calc)); //System.out.println("### (3) -->" + (measure[i][measure[1].length - 1] - calc)); // ///////////////////////////////////////////// // Uncomment the following lines for using the error handling for // different output bits // ///////////////////////////////////////////// // bit 0 fitness // For this fitness/bit we should see the following (d^b) double error = 100.0f - Math.abs(measure[i][measure[1].length - 1] - calc); // bit 1 fitness // For this fitness/bit we should see the following: (((b&d)^a)^c) // --> 1 // double error = 100.0f - Math.abs(measure[i][measure[1].length - // 2] - calc); // bit 2 fitness // For this fitness/bit we should see the following: // ((c|(d&b))&(a|c(&(d&b)))) -> 1 // double error = 100.0f - Math.abs(measure[i][measure[1].length - // 3] - calc); //System.out.println("### (4) --> error => " + error); //System.out.println("### (5) --> sum=" + sum); sum += error; } //System.out.println("### (6) --> sum=" + sum); this.currentFitness = sum / (measure[0].length * 100.0f); //System.out.println(" (7) fitness=>" + this.currentFitness); if (Double.isNaN(this.currentFitness)) { this.currentFitness = 0.01f; } return this.currentFitness; } public double calculateFitness() { currentFitness = calculateFullAdder(); System.out.println("________________________" + currentFitness); if (currentFitness < 0.0f) { currentFitness = 0.01f; } return currentFitness; } public String toString() { String strResult = ""; strResult += " --> " + this.formEquationString(); strResult += " --> " + currentFitness; return strResult; } public void copyGeneInfo(final Genome dest) { EquationGenome theGene = (EquationGenome) dest; theGene.length = length; theGene.theMin = theMin; theGene.theMax = theMax; } public Genome uniformCrossover(final Genome g) { EquationGenome aGene1 = new EquationGenome(); EquationGenome aGene2 = new EquationGenome(); g.copyGeneInfo(aGene1); g.copyGeneInfo(aGene2); // swap genes randomly EquationGenome crossingGene = (EquationGenome) g; for (int i = 0; i < length; i++) { if ((TheSeed.nextInt(100) % 2) == 0) { aGene1.theArray.add(crossingGene.theArray.get(i)); aGene2.theArray.add(theArray.get(i)); } else { aGene1.theArray.add(theArray.get(i)); aGene2.theArray.add(crossingGene.theArray.get(i)); } } // 50/50 chance of returning gene1 or gene2 EquationGenome aGene = null; if (TheSeed.nextInt(2) == 1) { aGene = aGene1; } else { aGene = aGene2; } return aGene; } public Genome crossover2Point(final Genome g) { final EquationGenome aGene1 = new EquationGenome(); final EquationGenome aGene2 = new EquationGenome(); g.copyGeneInfo(aGene1); g.copyGeneInfo(aGene2); // Pick a random crossover point int CrossoverPoint1 = nextInt(TheSeed, 1, (int) length); int CrossoverPoint2 = nextInt(TheSeed, CrossoverPoint1, (int) length); // normalize if (CrossoverPoint1 > CrossoverPoint2) { int temp = CrossoverPoint1; CrossoverPoint1 = CrossoverPoint2; CrossoverPoint2 = temp; } EquationGenome crossingGene = (EquationGenome) g; for (int j = 0; j < CrossoverPoint1; j++) { aGene1.theArray.add(theArray.get(j)); aGene2.theArray.add(crossingGene.theArray.get(j)); } for (int j = CrossoverPoint1; j < CrossoverPoint2; j++) { if (j >= 0) { aGene1.theArray.add(crossingGene.theArray.get(j)); aGene2.theArray.add(theArray.get(j)); } else { throw new RuntimeException( "<crossover2Point> j/crossoverpoint1 less than zero = " + j); } } for (int j = CrossoverPoint2; j < length; j++) { aGene1.theArray.add(theArray.get(j)); aGene2.theArray.add(crossingGene.theArray.get(j)); } // 50/50 chance of returning gene1 or gene2 EquationGenome aGene = null; if (TheSeed.nextInt(2) == 1) { aGene = aGene1; } else { aGene = aGene2; } return aGene; } public Genome crossover(final Genome g) { EquationGenome aGene1 = new EquationGenome(); EquationGenome aGene2 = new EquationGenome(); g.copyGeneInfo(aGene1); g.copyGeneInfo(aGene2); // Pick a random crossover point crossoverPoint = nextInt(TheSeed, 1, (int) length); EquationGenome crossingGene = (EquationGenome) g; for (int i = 0; i < crossoverPoint; i++) { aGene1.theArray.add(crossingGene.theArray.get(i)); aGene2.theArray.add(theArray.get(i)); } for (int j = crossoverPoint; j < length; j++) { if (j >= 0) { aGene1.theArray.add(theArray.get(j)); aGene2.theArray.add(crossingGene.theArray.get(j)); } else { throw new RuntimeException( "WARN: <crossover> j/crossoverpoint less than zero = " + j); } } // 50/50 chance of returning gene1 or gene2 EquationGenome aGene = null; if (TheSeed.nextInt(2) == 1) { aGene = aGene1; } else { aGene = aGene2; } return aGene; } // End of the Method Cross over } // End of the Class