Current Framework Version: 0.8.0
EvEqT is a simple library to help researchers evolve equation trees that can be used in genetic programming. The library provide a lot of operators and some default operators to help with the genetic operators (crossover and mutation).
There is more than one way to use that project:
- Copy the
eveqt
package from thesrc
folder to your projectsrc
folder. - Add
eveqt.jar
that can be found inbuild
folder as a dependency to your project.
Now you are ready to use the package check the Usage section
You can check Test.java
file for a full example on most of the functionalities that are available by EvEqT. Here is an example for couple of basic usages of EvEqT.
// Construct the parser object, that object will need a random object and two hashset
// varNames hashset contains all the possible variable names that should be used in the equation
// constValues hashset contains all the possible constants to be used by the system
// if you want to generate that constValues quickly, try using EvEqT.generateConstants(20, 1000);
EquationParser parser = new EquationParser(new Random(), varNames, constValues);
// You could the parser object to parse an equation you had written
// (make sure it is a correct equation or the system will throw exceptions at you)
EquationNode handEquation = parser.parse("sub(mul(add(jump, sub(log(6), 20)),dash),attack)");
// Or you could send the parser object to EvEqT helper functions to generate a random equation tree
// maxDepth is the maximum tree depth
EquationNode randomEquation = EvEqT.generateRandomTreeEquation(parser, maxDepth);
To calculate the value of any equation it is pretty simple:
// calculates the value of the equation using a dictionary of variable values
// varValues is a dictionary of all the defined variables in the hashset in the parser and their double value
System.out.println(equation.evalulate(varValues));
For modifications on an existing tree, you can check these functions:
// Return a new simplified version of the input equation if there is a group of nodes that are constant
EquationNode simpleEquation = EvEqT.simplifyTree(parser, equation);
// Delete a random node from a clone copy of the input equation
EquationNode deletedEquation = EvEqT.deleteNode(parser, equation);
// Change a random node from a clone copy of the input equation
EquationNode changeEquation = EvEqT.changeNode(parser, equation);
// Insert a new node to a clone copy of the input equation
EquationNode addEquation = EvEqT.insertNode(parser, equation, 5);
// generate a hybrid child from mixing the two input equations
EquationNode crossEquation = EvEqT.crossoverTrees(parser, equation1, equation2);
The system uses safe operators where it will return a fixed value for any NaN
value and big fixed value for any Infinity
or -Infinity
values. The default 1e10
for Infinity
, -1e10
for -Infinity
and 0
for NaN
. If you would like to change these values to any other value, use the following code:
// change the standard infinity value
EquationNode.infinityValue = 1e8;
// change the nan standard value
EquationNode.nanValue = 1;
- Ten different unary node operators
abs
: calculates the absolute value of the child nodefloor
: calculates the floor value of the child nodeceil
: calculates the ceiling value of the child nodeln
: calculates the natural logarithmic of the child nodeneg
: calculates the additive inverse of the child nodeinv
: calculates the multiplicative inverse of the child nodesigmoid
: calculates the sigmoid value of the child nodetanh
: calculates the tanh value of the child nodesin
: calculates the sin value of the child nodecos
: calculates the cos value of the child node
- Fourteen different binary operators:
add
: adds the values of the left and the right childrensub
: subtracts the value of the right child from the left childdivide
: divides the value of the right child from the left childmod
: calculates the modulus of the right child from the left childeq
: checks if both values are equal (1) or not (0)lg
: checks if the left node value larger than the right node value (1) or otherwise (0)ls
: checks if the left node value less than the right node value (1) or otherwise (0)max
: returns the maximum value of both the children valuesmin
: returns the minimum value of both the children valuesmul
: multiplies both children valuespow
: calculates the left child value to the power of the right child valuerand
: calculates a random double number between the left child value to the right child value
- Genetic modification functionalities
- generate a random tree
- delete a random node from a tree
- add a new node to a tree
- change terminal values or operator types
- mix two different equation trees
You need to create a class in eveqt.operators.unary
for your new operator where it will be extending UnaryOperator
class. That class need to implements the following functions:
/**
* calculate the result of the operator using the value coming from the child node
* this.child.evaluate(variables)
**/
@Override
public double evaluate(HashMap<String, Double> variables) {
...
}
/**
* return the string format of the equation, the format has to be
* "<operator-name>" + "(" + this.child.toString() + ")"
**/
@Override
public String toString() {
...
}
make sure that you remember the <operator-name>
because you will need to add it into two other places in the EquationParser
class in eveqt
package:
- The first location is to add to
unaryOperator
arraylist at the beginning of the class - The second location is to add it as a case in the switch statement in
getUnaryOperator
function in the middle of the class
You need to create a class in eveqt.operators.binary
for your new operator where it will be extending BinaryOperator
class. That class need to implements the following functions:
/**
* calculate the result of the operator using the values coming from the children node
* this.left.evaluate(variables) and this.right.evaluate(variables)
**/
@Override
public double evaluate(HashMap<String, Double> variables) {
...
}
/**
* return the string format of the equation, the format has to be
* "<operator-name>" + "(" + this.left.toString() + "," + this.right.toString() + ")"
**/
@Override
public String toString() {
...
}
make sure that you remember the <operator-name>
because you will need to add it into two other places in the EquationParser
class in eveqt
package:
- The first location is to add to
binaryOperator
arraylist at the beginning of the class - The second location is to add it as a case in the switch statement in
getBinaryOperator
function in the middle of the class
Bug reports and pull requests are welcome on GitHub at https://github.com/amidos2006/eveqt.
This code is available as open source under the terms of the MIT License.