Package com.heatonresearch.aifh.examples.gp

Source Code of com.heatonresearch.aifh.examples.gp.EvaluateExpression

/*
* Artificial Intelligence for Humans
* Volume 2: Nature Inspired Algorithms
* Java Version
* http://www.aifh.org
* http://www.jeffheaton.com
*
* Code repository:
* https://github.com/jeffheaton/aifh
*
* Copyright 2014 by Jeff Heaton
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package com.heatonresearch.aifh.examples.gp;

import com.heatonresearch.aifh.AIFHError;
import com.heatonresearch.aifh.genetic.trees.EvaluateTree;
import com.heatonresearch.aifh.genetic.trees.TreeGenomeNode;
import com.heatonresearch.aifh.randomize.GenerateRandom;

import java.util.Locale;

/**
* Evaluate expression.  This class shows how to construct a tree evaluator that will evaluate the following
* operators:
* <p/>
* add, sub, div, mul, negative, power, sqrt, as well as variables.
* <p/>
* This class could easily be modified to support additional operators.
*/
public class EvaluateExpression extends EvaluateTree {
    /**
     * The opcode for add.
     */
    public static final int OPCODE_ADD = 0;

    /**
     * The opcode for subtract.
     */
    public static final int OPCODE_SUB = 1;

    /**
     * The opcode for divide.
     */
    public static final int OPCODE_DIV = 2;

    /**
     * The opcode for multiply.
     */
    public static final int OPCODE_MUL = 3;

    /**
     * The opcode for negative.
     */
    public static final int OPCODE_NEG = 4;

    /**
     * The opcode for raise to the power.
     */
    public static final int OPCODE_POWER = 5;

    /**
     * The opcode for square root.
     */
    public static final int OPCODE_SQRT = 6;

    /**
     * The start of the constant and variable opcodes.
     */
    public static final int OPCODE_VAR_CONST = 7;

    /**
     * The constant values.
     */
    private double[] constValues;

    /**
     * The number of variables.
     */
    private int varCount;

    /**
     * The constructor.
     *
     * @param rnd           A random number generator.
     * @param numConst      The number of constants.
     * @param numVar        The number of variables.
     * @param minConstValue The minimum amount for a constant.
     * @param maxConstValue The maximum amount for a constant.
     */
    public EvaluateExpression(GenerateRandom rnd, int numConst, int numVar, double minConstValue, double maxConstValue) {
        this.constValues = new double[numConst];
        this.varCount = numVar;

        for (int i = 0; i < this.constValues.length; i++) {
            this.constValues[i] = rnd.nextDouble(minConstValue, maxConstValue);
        }
    }

    /**
     * Construct an evaluator with 1 variable, and 100 constants ranging between (-5,5)
     *
     * @param rnd A random number generator.
     */
    public EvaluateExpression(GenerateRandom rnd) {
        this(rnd, 100, 1, -5, 5);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int determineChildCount(int opcode) {
        switch (opcode) {
            case OPCODE_ADD:
                return 2;
            case OPCODE_SUB:
                return 2;
            case OPCODE_DIV:
                return 2;
            case OPCODE_MUL:
                return 2;
            case OPCODE_NEG:
                return 1;
            case OPCODE_POWER:
                return 2;
            case OPCODE_SQRT:
                return 1;
            default:
                return 0;
        }
    }

    /**
     * Get the text for an opcode.
     *
     * @param opcode The opcode.
     * @return The text for the opcode.
     */
    public String getOpcodeText(int opcode) {
        switch (opcode) {
            case OPCODE_NEG:
                return "-";
            case OPCODE_ADD:
                return "+";
            case OPCODE_SUB:
                return "-";
            case OPCODE_DIV:
                return "/";
            case OPCODE_MUL:
                return "*";
            case OPCODE_POWER:
                return "^";
            case OPCODE_SQRT:
                return "sqrt";
            default:
                int index = opcode - OPCODE_VAR_CONST;
                if (index >= (this.constValues.length + varCount)) {
                    throw new AIFHError("Invalid opcode: " + opcode);
                }
                if (index < this.varCount) {
                    return "" + ((char) ('a' + index));
                } else {
                    return String.format(Locale.US, "%.8f", this.constValues[index - varCount]);
                }
        }
    }


    /**
     * Display an expression as LISP (the programming language)
     *
     * @param node The root node.
     * @return The LISP for the expression.
     */
    public String displayExpressionLISP(TreeGenomeNode node) {
        StringBuilder result = new StringBuilder();

        if (determineChildCount(node.getOpcode()) == 0) {
            result.append(getOpcodeText(node.getOpcode()));
        } else {
            result.append("(");
            result.append(getOpcodeText(node.getOpcode()));
            for (TreeGenomeNode child : node.getChildren()) {
                result.append(" ");
                result.append(displayExpressionLISP(child));
            }
            result.append(")");
        }

        return result.toString();
    }


    /**
     * Display an expression as normal infix.
     *
     * @param node The root node.
     * @return The infix string.
     */
    public String displayExpressionNormal(TreeGenomeNode node) {
        StringBuilder result = new StringBuilder();

        if (determineChildCount(node.getOpcode()) == 0) {
            result.append(getOpcodeText(node.getOpcode()));
        } else {
            int childCount = determineChildCount(node.getOpcode());

            if (childCount == 0) {
                result.append(getOpcodeText(node.getOpcode()));
            } else {
                String name = getOpcodeText(node.getOpcode());

                if (name.length() > 1) {
                    result.append(name);
                    result.append("(");
                    boolean first = true;
                    for (TreeGenomeNode child : node.getChildren()) {
                        if (!first) {
                            result.append(",");
                        }
                        result.append(displayExpressionNormal(child));
                        first = false;
                    }
                    result.append(")");
                } else {
                    result.append("(");
                    if (childCount == 2) {
                        result.append(displayExpressionNormal(node.getChildren().get(0)));
                        result.append(name);
                        result.append(displayExpressionNormal(node.getChildren().get(1)));
                        result.append(")");
                    } else {
                        result.append(name);
                        result.append(displayExpressionNormal(node.getChildren().get(0)));
                        result.append(")");
                    }
                }
            }

        }


        return result.toString();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getVarConstOpcode() {
        return OPCODE_VAR_CONST;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getNumConst() {
        return this.constValues.length;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getNumVar() {
        return this.varCount;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public double evaluate(TreeGenomeNode node, double[] varValues) {
        switch (node.getOpcode()) {
            case OPCODE_NEG:
                return -(evaluate(node.getChildren().get(0), varValues));
            case OPCODE_ADD:
                return evaluate(node.getChildren().get(0), varValues) + evaluate(node.getChildren().get(1), varValues);
            case OPCODE_SUB:
                return evaluate(node.getChildren().get(0), varValues) - evaluate(node.getChildren().get(1), varValues);
            case OPCODE_DIV:
                return evaluate(node.getChildren().get(0), varValues) / evaluate(node.getChildren().get(1), varValues);
            case OPCODE_MUL:
                return evaluate(node.getChildren().get(0), varValues) * evaluate(node.getChildren().get(1), varValues);
            case OPCODE_POWER:
                return Math.pow(evaluate(node.getChildren().get(0), varValues), evaluate(node.getChildren().get(1), varValues));
            case OPCODE_SQRT:
                return Math.sqrt(evaluate(node.getChildren().get(0), varValues));
            default:
                int index = node.getOpcode() - OPCODE_VAR_CONST;
                if (index >= (this.constValues.length + varCount)) {
                    throw new AIFHError("Invalid opcode: " + node.getOpcode());
                }
                if (index < this.varCount) {
                    return varValues[index];
                } else {
                    return this.constValues[index - this.varCount];
                }
        }

    }
}
TOP

Related Classes of com.heatonresearch.aifh.examples.gp.EvaluateExpression

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.