geva.Mapper.GEGrammar.java Source code

Java tutorial

Introduction

Here is the source code for geva.Mapper.GEGrammar.java

Source

/*
Grammatical Evolution in Java
Release: GEVA-v1.2.zip
Copyright (C) 2008 Michael O'Neill, Erik Hemberg, Anthony Brabazon, Conor Gilligan 
Contributors Patrick Middleburgh, Eliott Bartley, Jonathan Hugosson, Jeff Wrigh
    
Separate licences for asm, bsf, antlr, groovy, jscheme, commons-logging, jsci is included in the lib folder. 
Separate licence for rieps is included in src/com folder.
    
This licence refers to GEVA-v1.2.
    
This software is distributed under the terms of the GNU General Public License.
    
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
/>.
*/

/*
 * GEGrammar.java
 *
 * Created on 13 October 2006, 10:23
 *
 */
package geva.Mapper;

import geva.Exceptions.BadParameterException;
import geva.Exceptions.MalformedGrammarException;
import geva.Individuals.GEChromosome;
import geva.Individuals.Phenotype;
import geva.Parameter.ParameterI;
import geva.Util.Constants;
import geva.Util.Enums;
import geva.Util.Random.MersenneTwisterFast;
import geva.Util.Structures.TreeNode;

import java.io.File;
import java.util.Properties;

import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Class for GEGrammar.
 * GEGrammar maps from a GEChromosome to a Phenotype
 * @author EHemberg
 */
public class GEGrammar extends ContextFreeGrammar implements ParameterI {
    private static Log logger = LogFactory.getLog(GEGrammar.class);
    private int PRCSetSize;
    private int PRCRange;
    private int PRCPrecision;
    GEChromosome genotype;
    Phenotype phenotype;
    int maxWraps;
    int usedWraps;
    int usedCodons;
    String name;
    DerivationTree dT;
    int maxDerivationTreeDepth;
    int maxCurrentTreeDepth;
    int dTNodeCount;
    private String derivationTreeType;

    /** Creates a new instance of GEGrammar */
    public GEGrammar() {
        super();
        this.maxWraps = 1;
    }

    /**
     * New instance
     * @param file file to read grammar from
     */
    public GEGrammar(String file) throws MalformedGrammarException {
        super();
        this.readBNFFile(file);
        this.maxWraps = 1;
    }

    public GEGrammar(StringBuilder bnfGrammar) throws MalformedGrammarException {
        super();
        readBNFString(bnfGrammar.toString());
        this.maxWraps = 1;
    }

    /**
     * New instance
     * @param p properties
     */
    public GEGrammar(Properties p) {
        super();
        this.setProperties(p);
    }

    /**
     * Copy constructor. Does not copy the genotype and phenotype
     * @param copy grammar to copy
     */
    public GEGrammar(GEGrammar copy) {
        super(copy);
        this.derivationTreeType = copy.getDerivationString();
        this.setMaxWraps(copy.getMaxWraps());
        this.maxWraps = copy.maxWraps;
        // A copy of the derivation tree should be here

        this.maxDerivationTreeDepth = copy.getMaxDerivationTreeDepth();
        this.maxCurrentTreeDepth = copy.getMaxCurrentTreeDepth();
        if (dT != null) {
            this.dT = new DerivationTree(copy.dT);
        }
        this.dTNodeCount = copy.getDTNodeCount();
        this.name = copy.name;
        this.maxDerivationTreeDepth = copy.getMaxDerivationTreeDepth();
        this.maxCurrentTreeDepth = copy.getMaxCurrentTreeDepth();
    }

    public void setProperties(Properties p) {
        setProperties(p, true);
    }

    /**
     * Set properties
     *
     * @param p object containing properties
     */
    public void setProperties(Properties p, boolean reloadFromFile) {
        String key;
        if (!getValidGrammar() || reloadFromFile) {
            String file = null;
            try {
                key = Constants.GRAMMAR_FILE;
                file = p.getProperty(key);
                if (file == null) {
                    throw new BadParameterException(key);
                }
            } catch (BadParameterException e) {
                logger.error(e + " No default grammar", e);
            }
            File f = new File(file);
            try {
                if (!f.exists()) { // try classloader
                    this.readBNFFile(file);
                } else {
                    this.readBNFFileFromFilesystem(file);
                }
            } catch (MalformedGrammarException ex) {
                logger.error("Failed reading grammar", ex);
                setValidGrammar(false);
            }
        }
        int value;
        try {
            key = Constants.MAX_WRAPS;
            value = Integer.parseInt(p.getProperty(key));
            if (value < 0) {
                throw new BadParameterException(key);
            }
        } catch (BadParameterException e) {
            value = 0;
            logger.error(e + " default wraps:" + value, e);
        }
        this.maxWraps = value + 1;

        try {
            this.PRCSetSize = Integer.parseInt(p.getProperty(Constants.PRC_SETSIZE, Constants.DEFAULT_PRC_SETSIZE));
            this.PRCRange = Integer.parseInt(p.getProperty(Constants.PRC_RANGE, Constants.DEFAULT_PRC_RANGE));
            this.PRCPrecision = Integer
                    .parseInt(p.getProperty(Constants.PRC_PRECISION, Constants.DEFAULT_PRC_PRECISION));

            if (PRCSetSize < 0) {
                throw new BadParameterException(Constants.PRC_SETSIZE);
            }
            if (PRCRange < 0) {
                throw new BadParameterException(Constants.PRC_RANGE);
            }
            if ((PRCPrecision < 0) || (PRCPrecision > 32)) {
                throw new BadParameterException(Constants.PRC_PRECISION);
            }
        } catch (BadParameterException e) {
            value = 0;
            System.out.println(e + " constant range:" + value);
        }
        if (PRCSetSize > 0) {
            generatePRC();
        }

        this.maxWraps = value + 1;
        this.maxDerivationTreeDepth = Integer.parseInt(
                p.getProperty(Constants.MAX_DERIVATION_TREE_DEPTH, Constants.DEFAULT_MAX_DERIVATION_TREE_DEPTH));
        this.derivationTreeType = p.getProperty(Constants.DERIVATION_TREE);
        if (this.maxWraps > 1 && this.derivationTreeType.equals("geva.Mapper.ContextualDerivationTree")) {
            throw new IllegalArgumentException("Wrapping must be turned off for Context Sensitive trees");
        }
    }

    /**
     * Map input to output
     * @return validity of mapping
     */
    public boolean genotype2Phenotype() {
        return genotype2Phenotype(false);
    }

    /**
     * Map output to input
     * @return validity of mapping
     */
    public boolean phenotype2Genotype() {
        return true;
    }

    /**
     * Replaces constants in the grammar with an array of randomly generated constants
     * @return 
     */
    public void generatePRC() {
        Rule oldRule = new Rule();
        oldRule = findRule("<prc>");

        if (oldRule != null) {
            System.out.println("<prc> rule found in grammar, generating constants");
            MersenneTwisterFast m = new MersenneTwisterFast();

            // creating rule to store constants
            Rule newRule = new Rule(PRCSetSize);
            newRule.setLHS(oldRule.getLHS());
            Symbol newSymbol = new Symbol();
            newSymbol.setType(Enums.SymbolType.TSymbol);

            for (int i = 0; i < PRCSetSize; i++) {
                //setting the precision and range to be used
                int divisor = (int) Math.pow(10, PRCPrecision);
                float constant = Math.abs((float) m.nextInt());
                constant = constant % (PRCRange * divisor); //set the Mod first
                constant = (constant / divisor);

                //converting to string
                StringBuffer strConst = new StringBuffer();
                strConst.append(constant);
                newSymbol.setSymbolString(strConst.toString());

                Production np = new Production();
                np.add(new Symbol(newSymbol));
                newRule.add(np);
            }

            //replacing old rule with new one.
            int x = rules.indexOf(oldRule);
            rules.remove(x);
            rules.add(x, newRule);
            System.out.println(
                    "PRC SetSize: " + PRCSetSize + " PRC Range: " + PRCRange + " PRC Precision: " + PRCPrecision);
            System.out.println("elements in the rule:" + newRule.toString());
        } else {
            System.out.println(
                    "Warning, PRC attributes specified but no <prc> rule in the grammar, no constants generated");
        }
    }

    /**
     * Clear the grammar
     */
    public void clear() {
        this.setValidGrammar(false);
        this.rules.clear();
        this.setStartSymbol(0);
        this.rules.clear();
    }

    /** Instanciates a derivation tree and calls buildDerivationTree() if
     * b is true else sets valid map to true 
     * @param b if tree should be built
     * @return validity of mapping
     */
    @SuppressWarnings({ "UnusedAssignment" })
    public boolean genotype2Phenotype(boolean b) {
        boolean validMap;
        if (b) {
            this.phenotype.clear();
            this.dT = TreeMill.getDerivationTree(this);
            validMap = dT.derive();
            setDerivationTree(dT);
            this.usedCodons = dT.getGeneCnt();
            this.usedWraps = dT.getWrapCount();
            this.maxCurrentTreeDepth = dT.getDepth();
            this.name = generateNameFromTree(dT);
            dT = null;//remove reference
        } else {
            validMap = true;
        }
        return validMap;
    }

    String generateNameFromTree(DerivationTree tree) {
        StringBuilder builder = new StringBuilder();
        Stack<DerivationNode> nodeStack = new Stack<DerivationNode>();
        nodeStack.push((DerivationNode) tree.getRoot());
        while (nodeStack.empty() == false) {
            DerivationNode nodes = nodeStack.pop();
            if (nodes != null) {
                if (nodes.getCodonIndex() != -1) {
                    builder.append(nodes.getCodonPick());
                }
                if (nodes.size() != 0) {
                    builder.append('[');
                    nodeStack.push(null);
                    for (int i = nodes.size(); i > 0; i--) {
                        nodeStack.push((DerivationNode) nodes.get(i - 1));
                    }
                }
            } else {
                builder.append(']');
            }
        }
        return builder.toString();
    }

    /**
     * Get a grammar of the right type
     * @param g grammar to create new instance of;
     * @return a new grammar object of the right type
     */
    public static GEGrammar getGrammar(final GEGrammar g) {
        final GEGrammar grammar;
        if (g instanceof GEGrammar) {
            grammar = new GEGrammar(g);
        } else {
            throw new IllegalArgumentException(g + " is not GEGrammar");
        }
        return grammar;
    }

    /**
     *  Get the max depth of the derivation tree built by the grammar
     * @return max derivation tree depth
     */
    public int getMaxCurrentTreeDepth() {
        return maxCurrentTreeDepth;
    }

    /**
     * Set the max depth of the derriation tree that was built by this grammar
     * @param maxCurrentTreeDepth
     */
    public void setMaxCurrentTreeDepth(int maxCurrentTreeDepth) {
        this.maxCurrentTreeDepth = maxCurrentTreeDepth;
    }

    /**
     * Get max wraps allowed
     * @return max wraps
     */
    public int getMaxWraps() {
        return maxWraps;
    }

    /**
     * Set max wraps
     * @param i max wraps
     */
    public void setMaxWraps(int i) {
        this.maxWraps = i;
    }

    /**
     * Set input
     * @param genotype input
     */
    public void setGenotype(GEChromosome genotype) {
        this.genotype = genotype;
    }

    /**
     * Set output
     * @param phenotype output
     */
    public void setPhenotype(Phenotype phenotype) {
        this.phenotype = phenotype;
    }

    public Phenotype getPhenotype() {
        return phenotype;
    }

    public GEChromosome getGenotype() {
        return this.genotype;
    }

    public void setPhenotype(Object p) {
        this.phenotype = (Phenotype) p;

    }

    public void setGenotype(Object g) {
        this.genotype = (GEChromosome) g;

    }

    /**
     * Get used inputs (codons in the genotype)
     * @return number of used inputs
     */
    public int getUsedCodons() {
        return this.usedCodons;
    }

    /**
     * Get used wraps (Number of times the input was reread from the start)
     * @return number of wraps
     */
    public int getUsedWraps() {
        return this.usedWraps;
    }

    public int getMaxDerivationTreeDepth() {
        return maxDerivationTreeDepth;
    }

    public void setMaxDerivationTreeDepth(int maxDerivationTreeDepth) {
        this.maxDerivationTreeDepth = maxDerivationTreeDepth;
    }

    /**
     * Set the derivation tree
     * @param derivation tree
     */
    public void setDerivationTree(DerivationTree dT) {
        this.dT = dT;
    }

    public DerivationTree getDerivationTree() {
        return dT;
    }

    /**
     * This method calculates an upper bound for the number of inputs needed 
     * to build a derivation tree according to the specified maxDerivationTreeDepth
     * and the max number of non terminals in a production of the grammars rules.
     * 
     * The upper bound is calculated as the sum of the max non terminals at each
     * depth of the tree. 
     * (length = Sum_i=0^D a^i, D=max depth, a = max non terminals in a production)
     * 
     * @return max number of inputs
     */
    public int getMaxChromosomeLengthByDepth() {
        int len = Integer.MAX_VALUE;
        if (this.maxDerivationTreeDepth < Integer.MAX_VALUE) {
            int maxNTProd = 0;
            // Get the maximum number of Non terminals in a production among the rules
            for (Rule r : rules) {
                for (Production p : r) {
                    if (maxNTProd < p.getNTSymbols()) {
                        maxNTProd = p.getNTSymbols();
                    }
                }
            }
            // Sum for each depth
            len = 0;
            for (int i = 0; i < this.maxDerivationTreeDepth; i++) {
                len += Math.pow(maxNTProd, i);
            }
        }
        return len;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        final GEGrammar that = (GEGrammar) obj;
        if (name != that.name && (name == null || name.equals(that.name) == false)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        if (name != null) {
            return name.hashCode();
        }
        return 0;
    }

    public int getDTNodeCount() {
        return this.dTNodeCount;
    }

    public void setDerivationTreeType(String derivationTreeType) {
        this.derivationTreeType = derivationTreeType;
    }

    @Override
    public String getDerivationString() {
        return this.derivationTreeType;
    }
}