Academia.eduAcademia.edu

GEVA: grammatical evolution in Java

2008, ACM Sigevolution

GEVA is an open source implementation of Grammatical Evolution in Java developed at UCD's Natural Computing Research & Applications group. As well as providing the characteristic genotype-phenotype mapper of GE a search algorithm engine and a simple GUI are also provided. A number of sample problems and tutorials on how to use and adapt GEVA have been developed.

GEVA - Grammatical Evolution in Java (v1.0) Michael O’Neill, Erik Hemberg, Conor Gilligan, Eliott Bartley, James McDermott, Anthony Brabazon Natural Computing Research & Applications Group University College Dublin Ireland Technical Report UCD-CSI-2008-09 December 5, 2008 Abstract GEVA is an open source implementation of Grammatical Evolution in Java developed at UCD’s Natural Computing Research & Applications group. As well as providing the characteristic genotype-phenotype mapper of GE a search algorithm engine and a simple GUI are also provided. A number of sample problems and tutorials on how to use and adapt GEVA have been developed. 1 Contents 1 Introduction 4 2 Grammatical Evolution 2.1 The Grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Genotype-Phenotype Mapping Process . . . . . . . . . . . . . . . 4 4 6 3 GEVA Design Overview 9 4 Installation Instructions & Running out-of-the-box 10 4.1 Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 5 Distribution Contents 14 6 Tutorial 0: The Demo Problems 6.1 HelloWorld . . . . . . . . . . . 6.2 L-systems . . . . . . . . . . . . 6.3 Paint . . . . . . . . . . . . . . . 6.4 Even-5-Parity . . . . . . . . . . 6.5 Santa Fe Ant trail . . . . . . . 6.6 Symbolic Regression . . . . . . 6.7 GUI Features . . . . . . . . . . 6.8 Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 16 17 19 19 19 20 20 20 7 Tutorial 1: Modifying Grammar Files 21 7.1 Modifying the HelloWorld Grammar . . . . . . . . . . . . . . . . 21 7.2 Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 8 Tutorial 2: Adding the Bonus Battleship Problem 8.1 Battleship . . . . . . . . . . . . . . . . . . . . . . . . 8.2 Fitness Function . . . . . . . . . . . . . . . . . . . . 8.3 Grammar . . . . . . . . . . . . . . . . . . . . . . . . 8.4 GEVA Bureaucracy . . . . . . . . . . . . . . . . . . 8.5 Building and running . . . . . . . . . . . . . . . . . . 8.5.1 Windows & Eclipse . . . . . . . . . . . . . . . 8.5.2 NetBeans . . . . . . . . . . . . . . . . . . . . 8.6 Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 23 23 24 25 25 26 26 27 9 Tutorial 3: Command Line Access 9.1 Changing Parameters . . . . . . . . . . 9.1.1 Command Line . . . . . . . . . . 9.1.2 Properties File . . . . . . . . . . 9.2 Changing the Problem/Fitness Function 9.3 Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 29 29 30 31 31 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Advanced Tutorials 10.1 Tutorial 4: How to Initialise a Population . . . . . . . . . . . . 10.1.1 Running the code . . . . . . . . . . . . . . . . . . . . . . 10.2 Tutorial 5: How to Construct a Simple Evolutionary Algorithm 10.2.1 Running the code . . . . . . . . . . . . . . . . . . . . . . 10.3 Tutorial 6: How to Add a New Fitness Function . . . . . . . . 10.3.1 A new fitness function . . . . . . . . . . . . . . . . . . . 10.3.2 Joining the Dots . . . . . . . . . . . . . . . . . . . . . . 10.3.3 Collecting Statistics . . . . . . . . . . . . . . . . . . . . 10.3.4 Running the code . . . . . . . . . . . . . . . . . . . . . . 10.3.5 Next Steps . . . . . . . . . . . . . . . . . . . . . . . . . 11 Conclusions . . . . . . . . . . 32 32 35 36 38 41 41 42 44 44 45 46 3 1 Introduction Grammatical Evolution in Java (GEVA) was developed at UCD’s Natural Computing Research & Applications group1 [14]. It is an open source implementation of Grammatical Evolution (GE) [30, 28, 29, 39] released under GNU GPL v3.0, which provides a search engine framework in addition to a simple GUI and the genotype-phenotype mapper of GE. This technical report serves as an introduction to the GEVA software providing guidelines on its installation and use. The software comes in two main parts, a simple GUI and the main GEVA package. The GUI provides a mechanism to explore the software and understand how it operates but use of the underlying GEVA can be accessed through a powerful command line interface to allow for scripting. In this first release some simple demonstration problems are provided to assist the user to gain an understanding of the code while reading the accompanying tutorials which are provided in this document and on the code’s website [14]. Following a brief introduction to Grammatical Evolution in Section 2, we describe the design of GEVA in Section 3, provide installation instructions in Section 4, and an introductory tutorials on its use in Sections 6, 7, 8, 9, followed by more advanced programming tutorials in Section 10. 2 Grammatical Evolution Grammatical Evolution (GE) (e.g., [30, 28, 4, 12, 13, 29, 39, 31, 19, 7, 10, 1, 32]) is a grammar-based form of Genetic Programming [38]. It marries principles from molecular biology to the representational power of formal grammars. GE’s rich modularity gives a unique flexibility, making it possible to use alternative search strategies, whether evolutionary, deterministic or some other approach, and to radically change its behaviour by merely changing the grammar supplied. As a grammar is used to describe the structures that are generated by GE, it is trivial to modify the output structures by simply editing the plain text grammar. This is one of the main advantages that makes the GE approach so attractive. The genotype-phenotype mapping also means that instead of operating exclusively on solution trees, as in standard GP, GE allows search operators to be performed on the genotype (e.g., integer or binary chromosomes), in addition to partially derived phenotypes, and the fully formed phenotypic derivation trees themselves. 2.1 The Grammar When tackling a problem with GE, a suitable BNF (Backus Naur Form) grammar definition must initially be defined. The BNF can be either the specification of an entire language or, perhaps more usefully, a subset of a language geared towards the problem at hand. 1 http://ncra.ucd.ie 4 In GE, a BNF definition is used to describe the output language to be produced by the system. BNF is a notation for expressing the grammar of a language in the form of production rules. BNF grammars consist of terminals, which are items that can appear in the language, e.g. binary boolean operators and, or, xor, and nand, unary boolean operators not, constants, true and false etc. and non-terminals, which can be expanded into one or more terminals and non-terminals. For example the grammar below can be used to generate boolean expressions, and <expr> can be transformed into one of three rules. It can become either ( <expr> <biop> <expr> ), <uop> <expr>, or <bool>. A grammar can be represented by the tuple {N, T, P, S}, where N is the set of non-terminals, T the set of terminals, P a set of production rules that maps the elements of N to T , and S is a start symbol which is a member of N . When there are a number of productions that can be applied to one element of N the choice is delimited with the ‘|’ symbol. For example N = { <expr>, <biop>, <uop>, <bool> } T = { and, or, xor, nand, not, true, false, (, ) } S = { <expr> } And P can be represented as: (A) <expr> ::= ( <expr> <biop> <expr> ) | <uop> <expr> | <bool> (B) <biop> ::= | | | and or xor nand (C) <uop> ::= not (D) <bool> ::= true | false The code produced will consist of elements of the terminal set T . The grammar is used in a developmental approach whereby the evolutionary process evolves the production rules to be applied at each stage of a mapping process, starting from the start symbol, until a complete program is formed. A complete program is one that is comprised solely from elements of T . In GEVA the BNF definition is comprised entirely of the set of production rules, with the definition of terminals and non-terminals implicit in these rules. The first non-terminal symbol is by default the start symbol. 5 As the BNF definition is a plug-in component of the system, it means that GE can produce code in any language thereby giving the system a unique flexibility. For the above BNF grammar, Table 1 summarises the production rules and the number of choices associated with each. Table 1: The number of choices available from each production rule. Rule Number Choices A 3 B 4 C 1 D 2 2.2 Genotype-Phenotype Mapping Process The genotype is used to map the start symbol as defined in the Grammar onto terminals by reading codons to generate a corresponding integer value, from which an appropriate production rule is selected by using the following mapping function: Rule = c mod r where c is the codon integer value, and r is the number of rule choices for the current non-terminal symbol. Consider the following rule from the given grammar, i.e., given the nonterminal <boolop>, which describes the set of boolean operators that can be used, there are four production rules to select from. As can be seen, the choices are effectively labelled with integers counting from zero. (B) <boolop> ::= | | | and or xor nand (0) (1) (2) (3) If we assume the codon being read produces the integer 6, then 6 mod 4 = 2 would select rule (2) xor. That is, <boolop> is replaced with xor. Each time a production rule has to be selected to transform a non-terminal, another codon is read. In this way the system traverses the genome. During the genotype-to-phenotype mapping process, it is possible for individuals to run out of codons, and in this case the wrap operator is applied 6 which results in returning the codon reading head back to the first codon in the individual. As such codons are reused when wrapping occurs. This is quite an unusual approach in evolutionary algorithms as it is entirely possible for certain codons to be used two or more times. This technique of wrapping the individual draws inspiration from the gene-overlapping phenomenon that has been observed in many organisms [24]. GE works with or without wrapping, and wrapping has been shown to be useful on some problems [28], however, it does come at the cost of introducing functional dependencies between codons that would not otherwise arise. In GE each time the same codon is expressed it will always generate the same integer value, but depending on the current non-terminal to which it is being applied, it may result in the selection of a different production rule. This feature is referred to as intrinsic polymorphism. What is crucial however, is that each time a particular individual is mapped from its genotype to its phenotype, the same output is generated. This is the case because the same choices are made each time. It is possible that an incomplete mapping could occur, even after several wrapping events, and typically in this case the mapping process is aborted and the individual in question is given the lowest possible fitness value. The selection and replacement mechanisms then operate accordingly to increase the likelihood that this individual is removed from the population. An incomplete mapping could arise if the integer values expressed by the genotype were applying the same production rules repeatedly. For example, consider an individual with three codons, all of which specify rule 0 from below. (A) <expr> ::= (<expr> <biop> <expr>) (0) | <uop> <expr> (1) | <bool> (2) Even after wrapping, the mapping process would be incomplete and would carry on indefinitely unless terminated. This occurs because the nonterminal <expr> is being mapped recursively by production rule 0, i.e., it becomes ( <expr> <biop> <expr> ). Therefore, the leftmost <expr> after each application of a production would itself be mapped to a ( <expr> <biop> <expr> ), resulting in an expression continually growing as follows: ( ( <expr> <biop> <expr> ) <biop> <expr> ) followed by ( ( ( <expr> <biop> <expr> ) <biop> <expr> ) <biop> <expr> ) and so on. Such an individual is dubbed invalid as it will never undergo a complete mapping to a set of terminals. For this reason an upper limit on the number of wrapping events that can occur is imposed. During the mapping process therefore, beginning from the left hand side of the genome codon integer values are generated and used to select rules from the BNF grammar, until one of the following situations arise: 1. A complete program is generated. This occurs when all the non-terminals 7 in the expression being mapped are transformed into elements from the terminal set of the BNF grammar. 2. The end of the genome is reached, in which case the wrapping operator is invoked. This results in the return of the genome reading frame to the left hand side of the genome once again. The reading of codons will then continue, unless an upper threshold representing the maximum number of wrapping events has occurred during this individual’s mapping process. 3. In the event that a threshold on the number of wrapping events has occurred and the individual is still incompletely mapped, the mapping process is halted, and the individual is assigned the lowest possible fitness value. To reduce the number of invalid individuals being passed from generation to generation various strategies can be employed. Strong selection pressure could be applied, for example, through a steady state replacement. One consequence of the use of a steady state method is its tendency to maintain fit individuals at the expense of less fit, and in particular, invalid individuals. Alternatively, a repair strategy can be adopted, which ensures that every individual results in a valid program. For example, in the case that there are non-terminals remaining after using all the genetic material of an individual (with or without the use of wrapping) default rules for each non-terminal can be pre-specified that are used to complete the mapping in a deterministic fashion. Another strategy is to remove the recursive production rules that cause an individual’s phenotype to grow, and then to reuse the genotype to select from the remaining nonrecursive rules. Also, by adopting a ramped-half-and-half initialisation based on derivation trees, it is possible to ensure that all genotypes in the initial population are completely mapped sentences in the target language. From this start state it can be difficult for invalid genotypes to propagate during a run with strong selection pressure, and also genetic operators which manipulate the derivation tree [18] can be used to ensure the generation of completely mapped sentences. There have been a number of extensions to GE in recent years in terms of the grammars adopted, the search engine and search operators employed, and even variants on the mapping process itself (e.g., see the following sources [31, 4, 13, 32, 12, 19, 5, 6, 20, 34, 21, 35, 26]). 2 2 Additional information on Grammatical http://www.grammatical-evolution.org 8 Evolution is available from 3 GEVA Design Overview The software comes in two main components, namely 1. GUI 2. GEVA The GUI (GUI.jar) provides a simple interface to assist in an initial exploration of the software. In reality the GUI simply invokes the main GEVA package (GEVA.jar) using the selected parameter set. The more advanced user can simply skip the GUI and work directly with the command line interface with GEVA.jar, thereby accessing the full unrestricted suite of features that exist in the current release. The GUI also provides a simple graphing utility, which is provided for informational purposes to aid the user in understanding the behaviour of GEVA. Figure 1: Modular components of Grammatical Evolution. An overview of the major components of Grammatical Evolution are provided in Fig. 1. 9 4 Installation Instructions & Running out-ofthe-box 1. A working installation of Java is required (at least Java 1.5). 2. Download the latest version of GEVA [14] from http://ncra.ucd.ie/geva. 3. Unzip the distribution, and navigate into the GEVA-v1.0/ directory. 4. To run out-of-the-box (i.e., in GUI mode) either (a) Double-click the GEVA_GUI.jar or (b) in a shell type java -jar GEVA_GUI.jar Figure 2: The GEVA Splash screen. A GEVA splash screen will be displayed first (see Fig. 2) followed by the main GUI window which allows you to select the problem and associated parameters. A number of sample problems are provided in the release. Running out-of-thebox GEVA uses the HelloWorld example problem by default. A screenshot of what the user sees is presented in Fig. 3. In this problem the goal is to match all the characters in a target character string (“geva”). To run this default problem with the default settings simply click on Run and the following screen will appear (see Fig. 4). You will see a fitness plot generated as the run progresses, and in this problem a solution tends to be found quite quickly so more than likely you will just see the fitness plot graph of the finished run. It is possible to modify the graph by checking the Visible 10 Figure 3: GEVA GUI screenshot for the default HelloWorld problem. The goal is to rediscover the string “geva” 11 box beside each data item, and it is also possible to change the colour associated with each data item. The GUI allows the user to plot a number of additional GE attributes by selecting the appropriate Tab (Codon, Invalids and Other are the current options). Under Codon it is possible to plot the average physical length of each individual in the population in terms of number of codons, and it is also possible to plot the average number of Used/expressed codons (i.e., codons that are actually used during the generation of the phenotype/solution). At any time it is possible to scale the graphs by right-clicking and dragging the graph along either axis. If you wish to save the resulting graph click on the Save Image button and a selection of file formats may be chosen from. Figure 4: GEVA GUI screen-shot of the graphing feature for the default HelloWorld problem. If you click on the Console tab you will see the following window, Fig. 5. This window simply captures the text dump that GEVA.jar generates upon execution and includes a print of the parameter settings, and the phenotype and fitness of the best solution ever found along with the total time GEVA was running for (in milliseconds) and the total number of generations. 4.1 Next Steps A description of the demonstration problems is presented in Section 6. It is recommended that the new user moves directly to this section (Tutorial 0). To gain a deeper understanding of how to modify the grammar (Tutorial 1), add your own simple problem (Tutorial 2), and use the command line interface (Tutorial 3) the more adventurous user can skip to Sections 7, 8 and 9 respectively. If you want to jump straight into the deep end and get your hands dirty coding your 12 Figure 5: GEVA GUI screen-shot of the console feature for the default HelloWorld problem. own search engine the more advanced user can visit the Advanced Tutorials in Section 10. Section 5 follows, which details the contents of the distribution. 13 5 Distribution Contents In the main distribution directory you will see the following files: Figure 6: GEVA main directory listing. bin/ contains the executables GEVA.jar and GUI.jar and associated libraries. build.xml is the build file used by ant to rebuild the entire distribution after modifying any of the source files. Seperate build files are available for the GUI and GEVA components in their respective directories. COPYING contains the text of the GNU GPL version 3. GEVA/ contains the source code, documentation, and build files for the GEVA code. GEVA GUI.jar is the main point of entry to execute the GUI version of GEVA. It invokes GUI.jar which is contained in the bin/ directory. GUI/ contains the source code, documentation, and build files for the GUI code. gui.config is used to initialise the configuration of the GUI so that it knows where GEVA.jar and the variours property and grammar files are located. LICENSE provides the Copyright notice and Licence information for the distribution. param/ contains two directories, Grammar/ which contains the grammar files for the demonstration problems, and the corresponding properties files are 14 contained in Parameters/. Also contained here are two additional configuration files for the GUI mode. These files tell the GUI what parameter and grammar files to associate with each demonstration problem (ff.config), and graph.config sets up some default settings for the graphing utility. testBuild.sh is used during build to test the operation of the code. 15 6 Tutorial 0: The Demo Problems From the GUI using the drop down Properties menu item you can change the problem used. The appropriate grammar, fitness function and default parameter settings are automatically set for you when you change between a problem using the Properties menu. When GEVA GUI.jar is run for the first time it runs the HelloWorld problem by default. A description of this and the other demonstration problems now follow. 6.1 HelloWorld In this simple problem the goal is to match the target string “geva”. Fitness is simply a count of the number of characters of the candidate solution which match the target string. As we are using search based upon minimisation, smaller fitness values are better, so we adjust the match count by subtracting it from the total character count (n) of the target string. F itness = targetStringLength − n X (targetChar[i] − predictedChar[i]) i=1 The example grammar (letter grammar.bnf) adopted simply generates strings of characters. The grammar is as follows: <string> ::= <letter>|<letter><string> <letter> ::= <vowel>|<consonant>|<space> <space> ::= _ <vowel> ::= a|o|u|e|i <consonant> ::= q|w|r|t|y|p|s|d|f|g|h|j|k|l|z|x|c|v|b|n|m A candidate solution is constructed beginning from the embryonic <string> symbol. A <string> can be replaced with either a <letter> or with <letter><string>. This means an output string can be anything from a single character to multiple characters. The <letter> symbol is used to determine which characters are included in the output string. These can be one of three items, a <vowel>, a <consonant> or a <space>. A space is represented by the underscore character , and this is the only possible replacement for a <space> symbol. It is therefore not necessary to consult the genome for a codon value in that instance. There are however five possible replacement choices for a <vowel> and twenty one choices for a <consonant>. Therefore, evolution has to search for a string of the correct length, and a string that contains the right sequence of characters to match the target string (“geva”). Click Run to see how GEVA performs on this problem. 16 6.2 L-systems To run the L-system problem select the LSystem.properties option from the Properties menu, and the default settings for an L-system demo are provided. This is an interactive form of GE that presents the user with the current population of L-systems (with duplicate phenotypes overlaid to save space). The user then determines which L-systems will become parents to create the next generation and/or can decide to purge individuals from the population (see Fig. 7). To create the next generation, select only those individuals that you want to become a Parent or to Purge, and click on Generate. Individuals that are not selected for either becoming a parent or purging are not used in the creation of the next generation of solutions. Purge forces that individual to be deleted from the population. To find out more about L-systems the reader is referred to Prusinkiewicz’s Algorithmic Beauty of Plants [37]. Figure 7: GEVA GUI screenshot of the L-system demo problem. Evolution in this case is driven by the user where the user directly acts as the selection operator determining which L-systems becomes parents to create the next population of candidate solutions. The default grammar adopted is LSys 1.bnf and is detailed below: <Sys> <n> ::=<n><angle><expr> ::=2|3|4 17 <angle> <expr> <op> <var> ::= ::= ::= ::= 20.0|22.5|25.0|27.5 <expr> <op> <expr> | [<expr> <op> <expr>] | <var> +|F The start symbol from which the L-system grammar is constructed is <Sys>. Evolutionary search determines the depth of expansion (<n>), the angle (<angle>) and production rules of each L-system. In this simple case we have restricted the depth of expansion to be either 2, 3 or 4, and limited the angles to four possibilities (20.0, 22.5, 25.0 and 27.5 degrees). When the symbol F is encountered a line is drawn. The symbols corresponding to <op> determine the angle the next line is drawn at. A second L-system grammar file, LSysEx 1.bnf, is provided as an example. This is similar to the grammar adopted in the generation of the NCRA group logo [34]. To activate the use of this grammar simply select it from the Grammar drop down menu in the GUI (see the menu item highlighted in blue in Fig. 8). Figure 8: Parameter settings of the L-system demo problem with the grammar choice sub-menu highlighted in blue. LSys 1.bnf is currently in use. Select LSysEx 1.bnf to create slightly more complicated L-systems. 18 6.3 Paint The Paint toy problem (Paint.properties), is provided which attempts to evolve the most complex colour picture possible where complexity refers to diversity of pixels. A screen dump of Paint in action is given in Fig. 9. The left-hand side of the picture continuously displays each individual in the population with the right-hand side presenting the most complex picture found to-date. Figure 9: GEVA GUI screen-shot of the Paint demo problem. The grammar adopted for the Paint problem is paint.bnf and is as follows: <paint> ::= | <intensity> <digit> ::= <intensity> <intensity> <intensity> <paint> <intensity> <intensity> <intensity> ::= <digit><digit> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 Each <digit> represents a color, and each painting is comprised of at least six colours. 6.4 Even-5-Parity This is the classic benchmark problem in which evolution attempts to find the five input even-parity boolean function. The grammar adopted here is efp grammar gr.bnf: <prog> ::= <expr> <expr> ::= <expr> <op> <expr> | ( <expr> <op> <expr> ) | <var> | <pre-op> ( <var> ) <pre-op> ::= not <op> ::= "|" | & | ^ <var> ::= d0 | d1 | d2 | d3 | d4 Select EvenFiveParity.properties from the Properties menu to run this problem. The optimal fitness is obtained when the correct output is generated for each of the 32 test cases. 6.5 Santa Fe Ant trail Select SantaFeAntTrail.properties from the Properties menu. The objective here is to evolve a program to control the movement of an artificial ant on a toroidal grid of size 32 by 32 units. 89 pieces of food are located along a broken trail, and the ant has 600 units of energy to find all the food. A unit of energy is 19 consumed when the ant uses one of the following operations: move(), right() or left(). The ant also has the capability to look ahead into the square directly facing it to determine if there is food present or not. The example grammar adopted here, sf grammar gr.bnf is as follows: prog> ::= <code> <code> ::= <line> | <code> <line> <line> ::= <condition>\n | <op>\n <condition> ::= if(food_ahead()==1) { <opcode> } else { <opcode> } <op> ::= left(); | right(); | move(); <opcode> ::= <op> | <opcode> <op> The ideal fitness is obtained when the ant has consumed all 89 pieces of food. 6.6 Symbolic Regression Select SymbolicRegression.properties from the Properties menu. The classic quartic function is used here x + x2 + x3 + x4 with 20 input-output test cases drawn from the range -1 to 1. Fitness is simply the sum of the errors, and an uncomplicated grammar adopted: <expr> ::= ( <op> <expr> <expr> ) | <var> <op> ::= +|-|* <var> ::= x0|1.0 In this particular instance prefix expressions are generated, and JScheme is used to evaluate the resulting candidate functions. 6.7 GUI Features In addition to changing between the different demonstration problems using the main GUI window it is also possible to: • modify any of the parameter settings including the choice of grammar, • save parameter settings to a new file, • delete a parameter settings file, • or load in previously saved parameter settings. 6.8 Next Steps The interested user can now gain a deeper understanding of how to modify the grammar (Tutorial 1), add your own simple problem (Tutorial 2), and use the command line interface (Tutorial 3) by reading Sections 7, 8 and 9 respectively. 20 7 Tutorial 1: Modifying Grammar Files After modifying parameter setting using the GUI, the simplest task is to alter the grammar for one of the demonstration problems. In GUI mode it is not currently possible to directly edit the grammar files provided. To modify a grammar: 1. Open the relevant grammar file in a text editor from the <GEVA_ROOT> /param/Grammar/ directory and be sure to save the modified file to the same location and give it a new name. 2. Return to the GUI and using the drop down menu for Grammar switch to the grammar file with the new name. 3. Run with the new grammar. We now walk the interested reader through a specific example of altering the grammar adopted for the default HelloWorld problem. 7.1 Modifying the HelloWorld Grammar The grammar for the HelloWorld demo problem is located in the directory called <GEVA_ROOT>/param/Grammar/. Open the file letter_grammar.bnf in your favourite text editor. You will see the following: <string> ::= <letter>|<letter><string> <letter> ::= <vowel>|<consonant>|<space> <space> ::= _ <vowel> ::= a|o|u|e|i <consonant> ::= q|w|r|t|y|p|s|d|f|g|h|j|k|l|z|x|c|v|b|n|m By default the Start Symbol of the grammar is the first non-terminal symbol that appears in the file. In this case <string> is the Start Symbol from which the mapping process will commence. In this grammar there are 2 possible replacements for <string>. It can become <letter> or it will be replaced with <letter><string>. This means that an output sentence (solution) from this grammar will be comprised of one or more <letter>s. In the above example a <letter> can be replaced with any one of <vowel>, <consonant> or <space>, where a <space> will become a terminal symbol ’ ’, a <vowel> can become any one of the five terminal symbols ’a’, ’o’, ’u’, ’e’, or ’i’, and finally a <consonant> can become any one of the 21 terminal symbols ’q’, ’w’, ’r’, ..., ’m’. The grammar can be easily modified such that a string could print additional characters. For example, this could be achieved by adding a new production rule for <letter>. The new rule might look like: <letter> ::= <vowel>|<consonant>|<space>|<symbol> 21 We then need to define the terminal symbol for the non-terminal <symbol>. This is achieved by adding a new set of productions rule to the grammar for <symbol>. The new grammar could now look like: <string> ::= <letter>|<letter><string> <letter> ::= <vowel>|<consonant>|<space>|<symbol> <space> ::= _ <vowel> ::= a|o|u|e|i <consonant> ::= q|w|r|t|y|p|s|d|f|g|h|j|k|l|z|x|c|v|b|n|m <symbol> ::= $ | \Euro To use this new grammar, start up GEVA as before. First navigate to the main GEVA directory (<GEVA_ROOT>/) and then either: 1. Double-click the GEVA_GUI.jar or 2. in a shell type java -jar GEVA_GUI.jar Now select the new grammar file from the Grammar drop-down menu, and click on Run. 7.2 Next Steps The interested user should now move on to Tutorial 2 to learn how to adapt the existing demo problems to create your own. Tutorial 2 walks through how you can modify your GEVA distribution to include an additional bonus demo problem, Battleship. 22 8 Tutorial 2: Adding the Bonus Battleship Problem The Advanced Tutorials described later explain in some detail how to build your own algorithms in GEVA. However, it is also possible (and much easier) to re-use the built-in algorithms to solve new problems. In this tutorial we will make some simple customisations to just 3 files and write a new fitness function, in order to solve a new problem: a simplified version of the game of Battleship. We will ignore questions of good style and software engineering practice. 8.1 Battleship Battleship is a paper-and-pencil game for two players, each possessing a grid representing a map of the sea, with the player’s own ships distributed throughout the grid. The aim is to fire at and sink the opponent’s ships, by guessing what cells they occupy. In this tutorial, the aim will be to evolve an optimal “firing pattern” for a fixed grid of enemy ships. The firing pattern will consist of multiple salvos, and each salvo will consist of multiple adjacent shots. This description should give a hint as to the type of grammar we will use. The aim will be to sink as many as possible of the ships using as few salvos and as few shots as possible. Each firing pattern will correspond to a single (evolutionary) individual, and after each individual is run, the grid will be reset with the ships intact and in the same places as before. Therefore, our version of Battleship will omit the in-game feedback and two-player aspects of the real game. 8.2 Fitness Function GEVA’s fitness evaluation functions are represented as classes which live in <GEVA_ROOT>/GEVA/src/FitnessEvaluation/ (where <GEVA_ROOT> represents the root directory of your GEVA download). Create a new directory under that location, named Battleship, and copy the file Battleship.java in there. This file contains not only the fitness evaluation code, but also (in our case) some hard-coded game logic and a method of visualising the success of an individual. You can find the file Battleship.java at http: //ncra.ucd.ie/geva/Battleship.java. Battleship.java was created firstly by copying an existing fitness evaluation function, <GEVA_ROOT>/GEVA/src/FitnessEvaluation/PatternMatch/ WordMatch.java. It may be instructive to view the differences between the two: they consist largely of logic specific to the two problem instances. The same copy-and-edit approach may be the easiest way to create new fitness functions of your own devising. The essential parts of the fitness evaluation class are that it imports FitnessEvaluation.FitnessFunction, it implements FitnessFunction, it has a constructor, it over-rides setProperties(), and it returns a (double) fitness value from evaluateString(). evaluateString() is where the real work 23 happens, and its structure is shown below. The first line converts the input phenotype into a string (without adding superfluous spaces). The body of the function adds to fitness every time it detects that a ship has been hit, with a bonus for each complete sinking, and subtracts for every salvo and every shot. Note that GEVA always minimises fitness, so in our example we take a safe reciprocal (1 / (1 + x)). public double evaluateString(Phenotype p) { String pS = p.getStringNoSpace(); double fitness; // parse pS and evaluate... return fitness; } Much of Battleship.java is hard-coded game logic, and is written in a rather C-like style which will offend native Java programmers. evaluateString() contains some code for printing (on the console) a visualisation of each individual’s success. The code is commented out by default, since it will slow the program down somewhat. This is regarded as a quick and dirty way of accomplishing this task. 8.3 Grammar Have a look at some of the existing grammars, which all have the suffix .bnf and live in <GEVA_ROOT>/param/Grammar/. They are written in Backus-Naur form, as explained elsewhere. In every case, the start symbol will be that on the left-hand side of the rule on the first line in the file. In our case, as hinted above, an individual (a “firing-pattern”) consists of multiple salvos separated by semi-colons, and each salvo consists of x- and y-coordinates and a size. Each of these is an integer with a limited range, as you can see in the code below. Paste it into a new file <GEVA_ROOT>/param/Grammar/Battleship.bnf. <pattern> ::= <salvo> | <salvo>;<pattern> <salvo> ::= <pos>,<pos>,<size> <pos> ::= <GECodonValue[0, 9]> <size> ::= <GECodonValue[1, 5]> Note the special GECodonValue non-terminals in this grammar. This is an easy way to put numerical values — in this case, integer values — into the phenotype. The current codon in the genome is mapped to produce a numerical value in the range given. For example, the fourth rule above is equivalent to <size> ::= 1|2|3|4|5. Double values can be produced by specifying the endpoints of the range with a decimal point or in scientific notation. The range may be closed (i.e. include the end-points), as above, or may be open (using round brackets, e.g. <GECodonValue(0, 6)>), or half-open at either end. There is also a special notation for producing a string from a given set: <GECodonValue{x, y, z}>. 24 8.4 GEVA Bureaucracy For the Battleship problem to run from the GEVA GUI, there are two more small tasks. Open the file <GEVA_ROOT>/param/ff.config and add the line FitnessEvaluation.Battleship.Battleship,Battleship.bnf just before the -jar line near the end. This tells the GEVA GUI that our new fitness function exists and corresponds to our new grammar. Next, copy the file <GEVA_ROOT>/param/Parameters/HelloWorld.properties to a new file in the same directory, Battleship.properties. Change the grammar file and fitness function entries as follows: grammar file=../param/Grammar/Battleship.bnf fitness function=FitnessEvaluation.Battleship.Battleship Also change the number of generations and population size as follows, so that initial experiments with Battleship will be quite short: generations=20 population size=20 This new .properties file gives all the configuration necessary for a single experiment with GEVA. When we start GEVA, this set of properties will be available as a preset experiment in the GUI (it can also be loaded as a preset on the command-line). 8.5 Building and running As you have modified some of the source code you now need to rebuild the jar files. To do this go to <GEVA_ROOT>/ and type ant <GEVA_ROOT>$ ant alternatively, you can use the allnotest parameter which makes the build a lot faster: <GEVA_ROOT>$ ant allnotest Note that you need to have ant [2] installed to do this! Otherwise you could use your favourite IDE to rebuild the jar files. The build.xml file is used by ant to recompile the modified source files and build fresh jar files. The <GEVA_ROOT>/build.xml file rebuilds all the jar files. If you prefer to use Eclipse or NetBeans we have include a description of some steps to build GEVA below in Sections 8.5.1 and 8.5.2. You should see a successful build happening. Java jar files will be placed in <GEVA_ROOT>/GEVA_GUI.jar, <GEVA_ROOT>/bin/GEVA.jar and <GEVA_ROOT> /bin/GUI.jar. Now your program can be used from the command-line or from its own GUI: GUI usage Go to <GEVA_ROOT>/ and type java -jar GEVA GUI.jar. In the first drop-down menu, select Battleship.properties (note that the configuration will change to reflect the .properties file we edited earlier), and click “run”. The program should again run with output in the GUI’s console. 25 Command-line usage Go to <GEVA_ROOT>/bin and type java -jar GEVA.jar -properties file ../param/Parameters/Battleship.properties and you should see the program running. If you wish to see visualisations of the game grid, uncomment the print statements in battleship.java, rebuild and re-run. In the console you will now see the ships gradually being sunk more and more successfully as the generations go by. 8.5.1 Windows & Eclipse Here are some notes especially for Windows and/or Eclipse users: 1. Download latest ’ant’ (Binary Edition). 2. Dowload latest JDK (e.g., jdk1.6.0_10), jdk version <1.5 does not work. 3. Add path of ant and JDK: Go to ’My Computer > Properties > Advanced Tab > Environmental Variables > Systematic Variables > Path > click Edit >’ add under this path add the following: <ANT_ROOT>\bin;<JAVA_ ROOT>\jdk1.6.0_10\bin after this, we can run from windows command line <GEVA_ROOT>\ant allnotest, in order to build the file; 4. Alternatively, download Eclipse instead of Binary Edition ’ant’ (since ’ant’ is bundled by default). Hence to build GEVA in windows, we can simply open <GEVA_ROOT>build.xml in Eclipse, and go to Run > External Tools > External Tools Configuration >: under Main> Buildfile: add <GEVA_ ROOT>\build.xml; under Main > Base Directory: add <GEVA_ROOT>; under Targets: check ’allnotest’ instead of the default one ’all’ (since on Windows it is not working); under JRE > Separate JRE, make sure, for example jdk1.6.0_10 is selected, or a more recent version of the jdk as appropriate to you. Click ’Run’ then GEVA should build successfully. 8.5.2 NetBeans 1. Choose project: for choose project select Java − > Java free-form project, this allows us to use the existing ant build script. 2. Name and location: specify the folder where you unpackaged all the code and it should pick up the build.xml contained within, you can set the project name to whatever you like. 3. Build and run actions: the build script automatically picks out the methods and assigns them correctly. 4. Source folder packages: as I am working with the GEVA source not the GUI I only added the folder <GEVA_ROOT>/GEVA/src but you can also add <GEVA_ROOT>/GEVA_GUI/src if you want to work with both. 26 5. Java source class path: there is a folder containing all the jars that are used for the main project <GEVA_ROOT>/GEVA/lib. you must add all the jar files not just their respective folders. 6. Project output: As this is specified by the build script you dont have to do anything and thats it! It should compile straight away without any errors. If you just want to work with the command-line form of GEVA instead of the GUI in Netbeans, you should furthermore: 7. Change relative path to absolute path: put the folder <GEVA_ROOT> /param in your project folder, like <project>/src/ (this is optional, but recommended) change the relative paths in all *.properties files (in /param/parameters folder) and constants.java file (in the folder <project>/src/Util/) to absolute paths for example: before change grammar_file = ../param/Grammar/HelloWorld_grammar.bnf after change grammar_file = <project>/src/param/Grammar/HelloWorld_grammar.bnf (according to upper folder change) 8. Run your code: then the IDE will show the output. 8.6 Next Steps The reader who feels that the fitness could have been calculated differently is certainly right and is invited to experiment. However, a more interesting project might involve altering the grammar and using the fitness function to encourage the evolution of re-use. If the concept of horizontal salvos with variable sizes had to be discovered by evolution, rather than being built-in as it is here, this game might provide a neat demonstration of the usefulness of re-use and automatically-defined functions. A description of how to use GEVA’s command line interface is now presented in Tutorial 3 (Section 9). 27 9 Tutorial 3: Command Line Access For those users who want more direct control and the ability to use GEVA with scripts a command-line interface is provided. To access this interface GEVA.jar, which is contained in the bin/ directory, should be used. In a shell navigate into <GEVA_ROOT>/bin, and you can run GEVA by typing java -jar GEVA.jar By default the HelloWorld demo problem will run with the default grammar and parameter settings. Output to stdout will be generated as follows: Loading properties from file system: ../param/Parameters/HelloWorld.properties mutation_probability=0.02 initialiser=Operator.RampedFullGrowInitialiser generations=1000 replacement_type=generational generation_gap=0.5 crossover_operation=Operator.Operations.SinglePointCrossover evaluate_elites=false userpick_size=20 grammar_file=../param/Grammar/letter_grammar.bnf grow_probability=0.5 population_size=100 output= fitness_function=FitnessEvaluation.PatternMatch.WordMatch max_wraps=3 selection_operation=Operator.Operations.TournamentSelect crossover_probability=0.7 mutation_operation=Operator.Operations.IntFlipMutation max_depth=10 elite_size=10 word=geva tournament_size=3 fixed_point_crossover=false stopWhenSolved=true Catch interval default: best individual Output directory is /Users/mike/Desktop/GEVA-v1/bin/ #---Data--Gen FitEvals Time(ms) Invalids BestFit AveFit VarFit AveUsedGenes AveLength 0 0 44 0 3.000 4.980 2.900 9.690 9.000 1 0 13 2 3.000 4.122 0.454 6.082 6.000 2 0 7 4 2.000 3.792 0.186 5.833 7.000 3 0 8 0 2.000 3.530 0.289 7.010 9.000 4 0 5 2 2.000 3.265 0.317 8.051 9.000 5 0 4 0 2.000 3.120 0.346 8.720 11.000 6 0 6 4 2.000 3.063 0.579 8.958 11.000 7 0 5 0 2.000 2.740 0.532 8.860 12.000 8 0 7 0 2.000 2.610 0.498 8.820 13.000 9 0 5 0 1.000 2.420 0.504 9.550 13.000 10 0 6 2 1.000 2.643 0.821 9.439 14.000 11 0 5 0 1.000 2.320 0.818 9.770 15.000 12 0 4 0 1.000 2.350 0.988 9.380 16.000 13 0 6 0 1.000 2.040 0.918 9.460 19.000 14 0 9 0 1.000 1.770 0.837 10.690 20.000 15 0 7 0 0.000 1.630 0.753 11.380 21.000 Rank:0 Fit:0.0 Phenotype:g e v a Done running: Total time(Ms) for 1000 generations was:219 As can be seen above the output includes the list of parameters and their settings, followed by a number of statistics for each generation of the run, and the fitness and phenotype of the best solution found. Finally the total runtime of GEVA in milliseconds is output. 28 9.1 Changing Parameters To change the parameters for the out-of-the-box GEVA there are two options. 1. Command line switches. 2. Modifying the Properties file. 9.1.1 Command Line In a shell you can manually override the default parameter settings. To see the standard parameters which can be changed use: java -jar GEVA.jar -h For convenience the output of the help switch is provided here: Commandline arguments -h for help -v for version -mutation_probability -initialiser -generations -replacement_type -generation_gap -crossover_operation -evaluate_elites -userpick_size -grammar_file -grow_probability -population_size -output -fitness_function -max_wraps -selection_operation -crossover_probability -mutation_operation -max_depth -elite_size -word -tournament_size -fixed_point_crossover -stopWhenSolved - To change the mutation probability to 0.1% java -jar GEVA.jar -mutation_probability 0.001 - To change the number of wrapping events 29 java -jar GEVA.jar -max_wraps 5 - To change the name of the output file to which run statistics are dumped java -jar GEVA.jar -output stats Note that a timestamp will be concatenated onto the filename you choose (e.g., in this case you might see something like stats11223421.dat). An example output statistics file is illustrated here: #bestFitness averageFitness averageUsedGeneLength time invalids varFitness aveLength 3.0 4.9 9.82 98 0 3.1500000000000012 9.0 3.0 3.878787878787879 6.03030303030303 19 1 0.20752984389348092 6.0 3.0 3.7 5.82 8 0 0.29 6.0 2.0 3.38 5.79 9 0 0.25559999999999966 6.0 2.0 3.29 5.85 10 0 0.24590000000000017 7.0 2.0 3.14 6.06 6 0 0.3004000000000002 7.0 2.0 2.91 6.65 7 0 0.4618999999999992 8.0 2.0 2.52 7.73 10 0 0.3495999999999999 9.0 2.0 2.5 7.62 6 0 0.49 10.0 2.0 2.47 7.67 9 0 0.5090999999999998 11.0 1.0 2.46 7.58 5 0 0.5084000000000001 12.0 1.0 2.38 8.24 8 0 0.4155999999999997 14.0 1.0 2.38 8.22 6 0 0.49559999999999976 14.0 1.0 2.11 8.94 8 0 0.39790000000000025 14.0 1.0 2.05 9.12 21 0 0.507500000000001 14.0 1.0 2.01 9.96 5 0 0.6899 14.0 1.0 2.19 10.01 8 0 0.8538999999999993 14.0 1.0 2.06 10.06 4 0 0.7163999999999995 15.0 1.0 2.19 10.44 4 0 1.0938999999999997 14.0 1.0 2.08 10.02 30 0 0.7736000000000008 13.0 1.0 2.08 10.16 5 0 0.9136000000000007 14.0 1.0 1.79 10.59 5 0 0.7659000000000001 16.0 1.0 1.82 10.69 4 0 0.6875999999999999 17.0 1.0 1.74 10.52 18 0 0.6923999999999998 17.0 1.0 1.64 11.28 4 0 0.5304000000000002 19.0 1.0 1.78 11.28 7 0 0.8115999999999997 19.0 1.0 1.81 10.88 6 0 0.9738999999999991 21.0 1.0 1.65 11.11 3 0 0.6874999999999991 22.0 1.0 1.59 10.93 3 0 0.6419000000000002 24.0 0.0 1.55 11.14 5 0 0.6874999999999997 29.0 9.1.2 Properties File To change parameter settings via the properties files, navigate to the directory containing the property files: <GEVA_ROOT>/param/Parameters/. Using your favourite text editor open the file of interest. To create a new properties file it is recommended to copy an existing file, or the TemplateProperties.properties file to a new file. When GUI version of GEVA is restarted the new property file will be automatically available from within the Properties drop-down menu. To call a specific properties file from the command line using the properties file switch. Go to <GEVA_ROOT>/bin and type java -jar GEVA.jar -properties file ../param/Parameters/<yourfilenamehere>.properties 30 9.2 Changing the Problem/Fitness Function GEVA includes out-of-the-box a number of example problems that can be easily switched between from the command line or the properties file. To work with new problems please refer to the Advanced Tutorials for an example of how this can be achieved. The simplest approach for any of the demo problems is to use all of the predefined parameter settings (which include the appropriate grammar) by using the correct properties file: HelloWorld: EvenFiveParity: L-system: Paint: SantaFeAnt: SymbolicRegression: java -jar GEVA.jar -properties file ../param/Parameters/HelloWorld.properties java -jar GEVA.jar -properties file ../param/Parameters/EvenFiveParity.properties java -jar GEVA.jar -properties file ../param/Parameters/LSystem.properties java -jar GEVA.jar -properties file ../param/Parameters/Paint.properties java -jar GEVA.jar -properties file ../param/Parameters/SantaFeAntTrail.properties java -jar GEVA.jar -properties file ../param/Parameters/SymbolicRegression.properties To select specific fitness functions and grammar files associated with some of the demo problems here are some further examples using the available problems from the command line. - HelloWorld java -jar GEVA.jar -fitness_function FitnessEvaluation.PatternMatch.WordMatch -grammar_file ../param/Grammar/letter_grammar.bnf In the case of the HelloWorld problem it is possible to modify the target string to something other than “geva” without modifying the code itself. Simply set a value for the parameter called word. For example, from the command line: java -jar GEVA.jar -word helloworld Here are examples for a selection of the other demo problems. - Even Five Parity java -jar GEVA.jar -fitness_function FitnessEvaluation.ParityProblem.EvenFiveParityFitnessBSF -grammar_file ../param/Grammar/efp_grammar_gr.bnf - Santa Fe Ant java -jar GEVA.jar -fitness_function FitnessEvaluation.SantaFeAntTrail.SantaFeAntTrailBSF -grammar_file ../param/Grammar/sf_grammar_gr.bnf - Symbolic Regression (x + x2 + x3 + x4 ) java -jar GEVA.jar -fitness_function FitnessEvaluation.SymbolicRegression.SymbolicRegressionJScheme -grammar_file ../param/Grammar/sr_grammar_sch.bnf 9.3 Next Steps The advanced user who now wants to jump straight into the deep end and get their hands dirty coding their own search engine should visit the Advanced Tutorials in Section 10. 31 10 Advanced Tutorials In this series of tutorials the user gets their hands dirty with Java code. We gradually expose how to construct an evolutionary algorithm with GEVA starting by simply initialising a population in Tutorial 4. Tutorial 5 then demonstrates how this population can be manipulated in an evolutionary loop by setting up the pipeline of operators that can be employed (e.g., selection, crossover and mutation). Tutorial 6 then outlines how a new fitness function can be created. 10.1 Tutorial 4: How to Initialise a Population To work through this tutorial navigate to <GEVA_ROOT>/GEVA/src/Main/Tutorials/ and open Tutorial4.java in your favourite code editor. The parameter settings for this tutorial are contained in <GEVA_ROOT>/param/Parameters/Tutorials/ Tutorial4.properties. package Main.Tutorials; import import import import import import import Algorithm.MyFirstSearchEngine; Algorithm.Pipeline; Algorithm.SimplePipeline; Main.AbstractRun; Mapper.GEGrammar; Util.Constants; Util.Random.MersenneTwisterFast; Figure 10: Tutorial 4 header details. Fig. 10 details the package and import statements necessary to setup a basic search algorithm in GEVA. Key components here are the use of the classes belonging to Algorithm to set up the basic architecture of the search engine itself. The Mapper class implements GE’s characterisitc genotype-phenotype mapper. The remaining statements import utilities such as the random number generator. Fig 11 outlines the signature of the Tutorial4 class, and it extends AbstractRun. A State can be considered a container class which is used to setup, initialise and run the algorithm. AbstractRun adds the parameter reading functionality to State. The constructor method Tutorial4() begins by setting up the pseudo-random number generator and then points to the location of the parameter file for this example. 32 /** * Tutorial4 main class. * This class is derived from the class State. State is conceptually the outer level * of a program created using GEVA, it is a container class for the algorithm and it * used to setup initialise and run the algorithm. AbstractRun provides parameter * reading functionality. You should try to familiarise yourself with GEVA’s parameterisation * mechanism(Covered in a later tutorial) as it will make your life much easier :) * * When Implementing a algorithm with GEVA it makes sense to extend AbstractRun, * and implement the method setup(String[] args). * @author erikhemberg */ public class Tutorial4 extends AbstractRun { /** Creates a new instance of Tutorial4 */ public Tutorial4() { this.rng = new MersenneTwisterFast(); super.propertiesFilePath = Constants.DEFAULT_PARAM_ROOT + "Paramaters/Tutorials/Tutorial4.properties"; } Figure 11: Tutorial 4 class signature and constructor details. The setup(String[]args) method is where all the magic happens in this example, see Fig. 12. The first order of business is to read in the command line arguments (if there are any). Next we setup the grammar which is read in from the current state of properties. The current state was read in from the properties file specified in the constructor method initially and the command line arguments modify this state. So this can be determined by either the properties file or overridden by using the appropriate command line switch. Now we start to setup the search algorithm engine itself by adopting the Algorithm interface. We then create the Initialiser module from the grammar, pseudo-random number generator and remaining properties. This module is later passed into the algorithm pipeline. This means we now need to create the pipeline for the algorithm. There are two pipelines assocated with an algorithm in GEVA. The first pipeline (pipelineInit) is used during the initialisation phase, the second pipeline (pipelineRun) during the main body of the algorithm (e.g. the evolutionary loop in the case of an Evolutionary Algorithm). The pipeline determines what actions take place in the execution of the algorithm, and of course their order of execution. SimplePipeline() is used to initialise the new pipeline, and we then tell the pipeline that it is the initialisation pipeline using alg. setInitPipeline(pipelineInit);. Once we have the pipeline established we can add modules to it. Earlier we created the initialistion module which contains all the details required to setup the first population of candidate solutions. Finally in this case we tell GEVA what algorithm to use with this.algorithm= alg;. 33 /** * Setup the algorithm. Read the properties. Create the modules(Operators) and operations * @param args The command line arguments */ public void setup(String[] args) { /* Read properties * You can configure many different aspects of GEVA * through the use of a properties file. While it is possible to configure * the modules using get/set methods we encourage you to learn how to use the * properties file and associated properties object to configure the system as * this makes it much easier to set up and change parameters for a run. * These properties can also be specified or overridden using the command line * arguments * * When you pass in an argument or an argument is read from the properties file * they are placed into a properties object. This object is passed to all modules’ * constructor methods and each module is responsible for reading its own arguments. * This makes parameterising easy by reducing the need for parameter setting in the * code. In fact it is possible to set up and configure different types of algorithms * using the supplied modules using only a properties file. */ // Creates properties from the command line arguments this.readProperties(args); /* * There are various steps to create an algorithm in GEVA. In this tutoral we only * intitalise a population. To get a better idea of what is going on, look at the * associated properties file Parameter/Tutorial4.properties */ //Grammar GEGrammar grammar = new GEGrammar(this.properties); //State has a data member Algorithm alg; Algorithm is an interface and //MyFirstSearchEngine is a simple but surprisingly flexible implementation. MyFirstSearchEngine alg = new MyFirstSearchEngine(); //Initialiser - One of he features of AbstractRun is that you can, //by using reflection, specify modules as parameters. //The method getInitialiser will return an initialiser as specified in the properties object. initialiser = getInitialiser(grammar, this.rng, this.properties); /* * Init * Here we create the initialisation pipeline. Algorithms derived from the base * class AbstractAlgorithm have two pipelines, pipelineInit and pipelineRun. * pipelineInit is run once at the start of an algorithm, so any initialisation * modules need to go on that pipeline. * In this tutorial we are simply going to create an instance of SimplePipeline(), * which as the suggests is a simple implementation of a pipeline. Pipelines are * at the heart of the way GEVA builds algorithms and they will be covered in more * detail in later tutorials. For now we simply need to add our initialiser module * to the initialisation pipeline. */ Pipeline pipelineInit = new SimplePipeline(); alg.setInitPipeline(pipelineInit); //Add modules to pipeline pipelineInit.addModule(initialiser); // Finally we set the algorithm this.algorithm = alg; } Figure 12: Tutorial 4 setup() method details. 34 /** * Run the state * @param args The command line arguments */ public static void main(String[] args) { try{ //Create the Tutorial4 object Tutorial4 mfs = new Tutorial4(); //Read the command-line arguments if(mfs.commandLineArgs(args)) { //Setup the algorithm. This calls the above setup method mfs.setup(args); //Initialize the algorithm. This runs the initialisation pipeline mfs.init(); System.out.println("Well done running: Tutorial4, now look at Tutorial5"); } } catch(Exception e) { System.err.println("Exception: "+e); e.printStackTrace(); } } Figure 13: Tutorial 4 main method details. The last step in this example is to write the main method to execute our pipeline. The code is detailed in Fig. 13. We start by calling the Tutorial4 constructor method, reading in the command-line arguments and finally calling the init() method to initialise our algorithm. 10.1.1 Running the code Now to test your code. Navigate into the <GEVA_ROOT> directory, and use ant [2] to rebuild the code. That is, assuming ant is installed type ant in your favourite shell. The build.xml file is used by ant to recompile the modified source files and build fresh jar files. The <GEVA_ROOT>/build.xml file rebuilds all the jar files. Once finished the build, navigate to the <GEVA_ROOT>/bin and type the following: java -classpath GEVA.jar Main.Tutorials.Tutorial4 The following will be output if successfully executed: Loading properties from file system: ../param/Parameters/Tutorials/Tutorial4.properties initial_chromosome_size=200 initialiser=Operator.Initialiser max_wraps=1 grammar_file=../param/Grammar/HelloWorld_grammar.bnf population_size=100 Well done running: Tutorial4, now look at Tutorial5 35 10.2 Tutorial 5: How to Construct a Simple Evolutionary Algorithm In Tutorial 4 we had a look at a simple algorithm that only initilised a population. In this tutorial we will show how to construct a simple algorithm. In GEVA algorithms are built by combining different modules into a pipeline. A module is a self-contained algorithm building block, by stacking modules an algorithm is created (You could create your entire algorithm in one module, but that is not what GEVA is designed for). Another tutorial will deal with creating your own modules, this tutorial only deals with the existing GEVA modules. A module should perform a single part of the algorithm, e.g mutation or selection. In this tutorial we will create a fairly standard evolutionary algorithm using tournament selection, int-flip mutation and single point crossover, the newly created individuals will replace the worst individuals in the population. This class is derived from the class State. State is conceptually the outer level of a program created using GEVA, it is a container class for the algorithm and it used to setup, initialise and run the algorithm. AbstractRun provides parameter reading functionality. You should try to familiarise yourself with GEVA’s parameterisation mechanism (covered in a later tutorial) as it will make your life much easier. When implementing an algorithm with GEVA it makes sense to extend AbstractRun, and implement the method setup(String[]args). The setup method is identical to Tutorial4 up to setting up the Initialiser module. The first new item is the creation of a crossover module as detailed in Fig. 14. /* * CROSSOVER * To implement crossover. First a crossover operation needs to be chosen. * Here it is single point crossover. To the operation a reference to the * random number generator is passed as well as the properties. The crossover * operation class will identifie which of the properties it will consider * for its settings, the rest will be ignored. * * After the operation is instanciated a CrossoverModule object is created, * which takes a reference to the crossover operation and sets it as the * operation performed by the module. */ CrossoverOperation singlePointCrossover = new SinglePointCrossover(this.rng, this.properties); CrossoverModule crossoverModule = new CrossoverModule(this.rng, singlePointCrossover); Figure 14: Tutorial 5 crossover module details. In this case a one-point crossover operator is employed (singlePointCrossover. To create a crossover module the actual crossover type used (CrossoverOperation) and a pseudo-random number generator are required. The next step sees the creation of a mutation module, which adopts an integer-based mutation. Codons in GEVA are integers by default. The integer mutation randomly picks an integer to replace the current codon value. You will notice a strong similarity to the creation of the crossover module (see Fig. 15). 36 /* * MUTATION * The same as for crossover, except that a mutation operation * and a mutation module are created. */ IntFlipMutation mutation = new IntFlipMutation(this.rng, this.properties); MutationOperator mutationModule = new MutationOperator(this.rng, mutation); Figure 15: Tutorial 5 mutation module creation details. Fig. 16 outlines the creation of the selection and replacement modules, which is achieved in a similar fashion to crossover and mutation. The difference in this case is the choice of strategy in each case is read from the properties state (these were set either from the properties file or through the command-line). The choice of mutation and crossover are effectively hard-coded in this tutorial example. /* * SELECTION * A selection operation is created by calling getSelectionOperation, to, * via reflection, create a SelectionOperation. The SelectionOperation * class to instanciate is specified in the properties file. As with * crossover this is passed to the SelectionScheme module. */ SelectionOperation selectionOperation = getSelectionOperation(this.properties, this.rng); SelectionScheme selectionScheme = new SelectionScheme(this.rng, selectionOperation); /* * REPLACEMENT * Again similar procedure to crossover when creating the replacement * operation. For the module creation reflection is used. This is * because there are different ways of joining the new and old * populations. Another important thing to notice for the replacement * is that it needs to know which population it will join. Here it takes * the reference from selectionScheme.getPopulation(), in other words * the selected population. */ ReplacementOperation replacementOperation = new ReplacementOperation(this.properties); JoinOperator replacementStrategy = this.getJoinOperator(this.properties, this.rng, selectionScheme.getPopulation(), replacementOperation); Figure 16: Tutorial 5 the creation of the selection and replacement modules. Now we create the pipelines. The initialisation pipeline is created in an identical manner to Tutorial1. The difference in this tutorial is that we setup the LoopPipeline, and the details are provide in Fig. 17. Up to this point we have established the various operators (modules) that will comprise the search algorithm. The next step is to associate the relevant population with the different modules (see Fig. 18). The selection module takes the initial population, and the replacement module also takes the initial popula37 /* * LOOP * Here we create the loop pipeline, this is what will be run after the * initialisation. It is to this pipeline that all the modules should be * attached. It is important to consider the execution order of the modules, * and which population they will be working on. */ Pipeline pipelineLoop = new SimplePipeline(); alg.setLoopPipeline(pipelineLoop); Figure 17: The creation of the LoopPipeline in Tutorial 5. tion in addition to the population output by population created by the selection scheme. The initial population is equivalent to the current population in an EA and the selection scheme population is equivalent to a temporary population of children which is used to create the next generation in combination with the current population members. The crossover and mutation modules then take the selection scheme population. /* * POPULATIONS * Here the populations that the different modules will work on is set. * Remember that we set the population which would be join when we * constructed the module. Here the modules work on either the * initialised population or the selected population. Finally both * populations are in the replacementStrategy module. */ selectionScheme.setPopulation(initialiser.getPopulation()); // The selectionScheme takes one population and splits it replacementStrategy.setPopulation(initialiser.getPopulation()); // The replacement takes two populations and joins them // The population that will be joined is specified in the constructor. crossoverModule.setPopulation(selectionScheme.getPopulation()); // Crossover will be performed on the selected population mutationModule.setPopulation(selectionScheme.getPopulation()); // Mutation will be performed on the selected population Figure 18: pipelines. Associating populations with the different modules from the Finally we add the modules to the loop pipeline in the order in which we wish them to be executed. This is outlined in Fig. 19. Then we create our main method, which is the same as in the previous tutorial except we can run the loop pipeline on this occasion as can be seen in Fig. 20 using the run() method. 10.2.1 Running the code Now to test your code follow the same steps as for the last tutorial. Navigate into the <GEVA_ROOT> directory, and use ant [2] to rebuild the code. That is, assuming ant is installed type ant in your favourite shell. The build.xml file is 38 /* * PIPELINE * Here the modules are added in the desired order to the loop pipeline. * First selection will be performed. After that crossover will be * performed, remember that the crossover module will operate on the * selected population. This was set above, when the setPopulation was * called. Then the selected population will be mutated. Finally the * replacementStartegy modul will replace the old population * with the selected population. */ pipelineLoop.addModule(selectionScheme); //Select the population according to the in the properties //file specified criteria, here tournament selection pipelineLoop.addModule(crossoverModule); //Perform crossover on the setPopulation, here the selected //population will be subjected to single point crossover pipelineLoop.addModule(mutationModule); //Mutate the setPopulation. Here int-flip muatation is //performed on the selected population pipelineLoop.addModule(replacementStrategy); //Replace the old population with the selected population. Figure 19: Adding modules to the pipeline in Tutorial 5. /** * Run the state * @param args The command line arguments */ public static void main(String[] args) { try{ //Create the Tutorial5 object Tutorial5 mfs = new Tutorial5(); //Read the command-line arguments if(mfs.commandLineArgs(args)) { //Setup the algorithm. This calls the above setup method mfs.setup(args); //Initialize the algorithm. This runs the initialisation pipeline mfs.init(); // Run the algorithm int its = mfs.run(); //Returns the number of iterations performed System.out.println("Well done running: Tutorial5 for "+its+", now look at Tutorial6"); } } catch(Exception e) { System.err.println("Exception: "+e); e.printStackTrace(); } } Figure 20: The main method for Tutorial 5 which executes the loop pipeline. 39 used by ant to recompile the modified source files and build fresh jar files. The <GEVA_ROOT>/build.xml file rebuilds all the jar files. Once finished the build, navigate to the <GEVA_ROOT>/bin and type the following: java -classpath GEVA.jar Main.Tutorials.Tutorial5 The following will be output if successfully executed: Loading properties from file system: ../param/Parameters/Tutorials/Tutorial5.properties initialiser=Operator.Initialiser selection_operation=Operator.Operations.TournamentSelect tournament_size=3 grammar_file=../param/Grammar/HelloWorld_grammar.bnf replacement_type=steady_state fixed_point_crossover=true crossover_probability=0.9 initial_chromosome_size=200 mutation_probability=0.05 population_size=100 max_wraps=1 Well done running: Tutorial5 for 5000, now look at Tutorial6 40 10.3 Tutorial 6: How to Add a New Fitness Function In Tutorial 5 we walked through an example of how a simple Genetic Algorithm could be implemented using GEVA without any fitness evaluation. In this tutorial we will show how to add a simple symbolic regression fitness evaluation to the algorithm. In the demonstration problems outlined earlier in this document a Symbolic Regression example was introduced in which fitness was calculated using the JScheme interpreter. JScheme is a dialect of scheme with a simple java interface [22]. That is, solutions to the demo Symbolic Regression problem were output in the JScheme language. One of the advantages of adopting the Grammatical Evolution approach to Genetic Programming is the flexibility of language choice that it allows. Effectively you can output code in any language and use a compiler for that language to create an executable which can be executed to calculate a fitness. Alternatively, if it is an interpreted language you can use the interepeter for fitness calculation. In this Tutorial we outline an alternative approach to the demo problem where we generate symbolic expressions in the Java language and use the Bean Scripting Framework [8] and Groovy [17] to dynamically evaluate them. 10.3.1 A new fitness function A fitness function which uses the Bean Scripting Framework is provided in <GEVA_ROOT>/GEVA/src/FitnessEvaluation/SymbolicRegression/SymbolicRegressionBSF.java. The code is reproduced in Fig. 21. You can see that this class extends the InterpretedFitnessEvaluationBSF class which can be found in <GEVA_ROOT>/GEVA/src/FitnessEvaluation/InterpretedFitnessEvaluationBSF.java In the createCode method contained in SymbolicRegressionBSF.java we basically write a Java class as a string and dynamically load in the evolved individual using the code.append(p.getString()); statement. This Java code in the form of a string is then used in the runFile method in the InterpretedFitnessEvaluationBSF.java class. This string (Java code) is then passed to the Bean Scripting Framework and Groovy to evaluate its fitness. Now that we have our new fitness function which evaluates code output in Java, we can now add this to the algorithm from the main method of this tutorial. 41 package FitnessEvaluation.SymbolicRegression; import FitnessEvaluation.InterpretedFitnessEvaluationBSF; import Individuals.Phenotype; import java.util.Properties; /** * Evaluates the fitness for the SymbolicRegressionExperiment class. The help class SymRegFunk * is used to evaluate the arithmetic expressions. * @author jonatan */ public class SymbolicRegressionBSF extends InterpretedFitnessEvaluationBSF { /** Creates a new instance of SymbolicRegression */ public SymbolicRegressionBSF() { } public void setProperties(Properties p) { } public String createCode(Phenotype p) { StringBuffer code = new StringBuffer(); //Header code.append("package FitnessEvaluation.SymbolicRegression;\n"); code.append("public class Test extends SymRegFunkBSF {\n"); code.append("\tpublic Test() {}\n"); code.append("\tpublic double expr(double X) {\n\t\treturn "); //Input code.append(p.getString()); //Tail code.append("\n\t}\n}\n"); code.append("test = new Test()\ntest.getFitness()"); return code.toString(); } } Figure 21: A simple Fitness function which adopts the Bean Scripting Framework to dynamically evaluate Java code. 10.3.2 Joining the Dots As in Tutorials 4 and 5, again we start with the setup() method with the difference this time that we add in code to identify which fitness function to use. Fig. 22 outlines the statements necessary to achieve this where the fitness function to adopt is specified from the properties object whose state has been determined by either the properties file, or command line arguments, or both. In GEVA fitness evaluation is peformed by an operation called fitnessEvaluationOperation. The FitnessEvaluationOperation uses the fitnessFunction to calculate fitness by calling the getFitness method of a FitnessFunction object. The FitnessEvaluator is then used to pass the fitness function to the algo42 /* * FITNESS FUNCTION * The fitness function is determined dynamically by getFitnessFunction. * Where the fitness function is specified in the properties file. * A fitness function implements the interface FitnessFunction, this * interface requires it to implement getFitness(Individual i). * It is there that the fitness evaluation should be written. In this * example the fitness evaluation consists of matching the string * that an individual maps to a predifined string. This tutorial * demonstrates a simple case which does not involve compiling. * * The FitnessEvaluationOperation takes the fitness function as an * argument and calls the getFitness method in the FitnessFunction. * This operation checks if the individual is already evaluated, * mapped and valid. In this tutorial only unevaluated individuals with * valid mappings will be sent to the fitness function. * In GE the individual can be invalid if the there are non-terminals * still present in the developing solution after we have read all * the codons on the genome. * * A FitnessEvaluator module contains the operation and is what is * attached to the pipeline. */ FitnessFunction fitnessFunction = getFitnessFunction(this.properties); FitnessEvaluationOperation fitnessEvaluationOperation = new FitnessEvaluationOperation(fitnessFunction); FitnessEvaluator fitnessEvaluator = new FitnessEvaluator(this.rng, fitnessEvaluationOperation); Figure 22: Tutorial 6 code to state which FitnessFunction to adopt. FitnessEvaluator fitnessEvaluatorInit = new FitnessEvaluator(this.rng, fitnessEvaluationOperation); fitnessEvaluatorInit.setPopulation(initialiser.getPopulation()); Figure 23: Addition of the FitnessEvaluator to the initialisation pipeline. rithm pipelines. We can see the code making the addition to the initialisation pipeline in Fig. 23. Before we add the FitnessEvaluator to the main loop pipeline we must first tell it which population to operate on (see Fig. 24) and then add it to the loop pipeline in Fig. 25. fitnessEvaluator.setPopulation(selectionScheme.getPopulation()); // Fitness evaluation will be performed on the selected population Figure 24: Tell the FitnessEvaluator which population to operate on in the main loop pipeline. 43 pipelineLoop.addModule(fitnessEvaluator); //The population will be assigned new fitness Figure 25: Addition of the FitnessEvaluator to the main loop pipeline. 10.3.3 Collecting Statistics In the example code we have also included the ability to capture some statistics about the evolving population (see Fig. 26). //Statistics StatCatcher stats = new StatCatcher(Integer.parseInt(this.properties.getProperty("generations"))); IndividualCatcher indCatch = new IndividualCatcher(this.properties); stats.addTime(startTime); //Set initialisation time for the statCatcher (Not completly accurate here) StatisticsCollectionOperation statsCollection = new StatisticsCollectionOperation(stats, indCatch, this.properties); Collector collector = new Collector(statsCollection); ... collector.setPopulation(initialiser.getPopulation()); //set population that collector works on pipelineInit.addModule(collector); // add collector to the initialisation pipeline ... pipelineLoop.addModule(collector); // add collector to the main loop pipeline Figure 26: Addition of the statistics collector. 10.3.4 Running the code Now to test your code follow the same steps as for the other tutorials. Navigate into the <GEVA_ROOT> directory, and use ant [2] to rebuild the code. That is, assuming ant is installed type ant in your favourite shell. The build.xml file is used by ant to recompile the modified source files and build fresh jar files. The <GEVA_ROOT>/build.xml file rebuilds all the jar files. Once finished the build, navigate to the <GEVA_ROOT>/bin and type the following: java -classpath GEVA.jar Main.Tutorials.Tutorial6 Something along the lines of the following will be output if successfully executed: Loading properties from file system: ../param/Parameters/Tutorials/Tutorial6.properties fitness_function=FitnessEvaluation.SymbolicRegression.SymbolicRegressionBSF initialiser=Operator.Initialiser selection_operation=Operator.Operations.TournamentSelect tournament_size=3 44 grammar_file=../param/Grammar/sr_grammar_gr.bnf replacement_type=steady_state fixed_point_crossover=true crossover_probability=0.9 initial_chromosome_size=200 mutation_probability=0.05 population_size=10 max_wraps=1 generations=2 Catch interval default: best individual #---Data--Gen FitEvals Time(ms) Invalids BestFit AveFit VarFit AveUsedGenes AveLength AveDTDepth 0 0 554 7 12.767 19.792 24.676 3.333 200.000 3.667 5 0 332 2 12.767 18.035 27.760 4.000 200.000 4.000 10 0 441 0 12.767 13.820 9.994 5.600 200.000 4.800 Rank:0 Fit:12.766599999999995 Phenotype:sin ( sin ( X ) ) Well done running: Tutorial6 for 10, now look at Tutorial7 10.3.5 Next Steps This tutorial demonstrated how you can write your own fitness function to determine the fitness of a candidate solution regardless of the language in which it is written. The original demo Symbolic Regression instance used a dialect of Scheme to represent the solutions and this tutorial output simple Java expressions which were then dynamically evaluated using Groovy and the Bean Scripting Framework. For symbolic regression it is often the case that we wish to optimise the speed at which we can evaluate solutions, so it is common to code your own interpreter for simple prefix expressions for example. As a next step the user interested in Symbolic Regression should consider writing their own specialised fitness function with a built-in interpreter to suit their specific needs. 45 11 Conclusions GEVA is available for download from the UCD NCRA group website http: //ncra.ucd.ie/geva or http://www.grammatical-evolution.org. Included in the release are instructions on how to run GEVA out-of-the-box, and more detailed tutorials for those who wish to modify the software for new purposes. We also welcome feedback on the software as we plan to actively maintain the code, releasing new versions as features are added. A GEVA Google group has been set up to facilitate communication amongst the GEVA community [15]. We hope that GEVA will be a useful resource for the EC community and beyond. Acknowledgments We would like to thank past and present members of the UCD Natural Computing Research & Applications group, especially Tiberiu Simu, Jonathan Huggoson, and Jeff Wright for initial testing and some additions to the code. GEVA was beta-tested by the students of COMP30290 Natural Computing, an elective offered by UCD School of Computer Science & Informatics [27], from September to November 2007, and again from September to November 2008, and by Patrick Middleburgh who developed the seed of the LSystem interface as part of his Final Year Computer Science project at UCD. We are grateful to Edgar Galvan, Jonathan Byrne, Wei Cui, Jing Dang, John Mark Swafford, Uy Nguyen and Kai Fan for their comments on an earlier version of this document. We would also like to thank Miguel Nicolau for many interesting discussions that helped inform the design of GEVA, in particular the genotype-phenotype mapper which draws upon the design adopted in Miguel’s libGE C++ library. This publication has emanated from research conducted with the financial support of Science Foundation Ireland under Grant No. 06/RFP/CMS042, and UCD Research Seed Funding. References [1] Amarteifio S. (2005). Interpreting a Genotype-Phenotype Map with Rich Representations in XMLGE, Masters Thesis, University of Limerick. Available from http://ncra.ucd.ie/downloads/pub/ SaoirseMScThesis.pdf [2] Apache Ant. http://ant.apache.org/manual/index.html. [3] Berarducci P., Jordan D., Martin D., Seitzer J. (2004). GEVOSH: Using Grammatical Evolution to Generate Hashing Functions. In Proceedings of Genetic and Evolutionary Computation Conference (GECCO2004) workshop program. [4] Brabazon, A., O’Neill, M. (2006). Biologically Inspired Algorithms for Financial Modelling. Springer. 46 [5] Brabazon A., O’Neill M. (2006). Credit Classification Using Grammatical Evolution. Informatica, pp.325-335 Vol.30 No.3. [6] Brabazon A., O’Neill M. (2008). Bond Rating with πGrammatical Evolution. Knowledge-Driven Computing, pp.17-30 Springer. [7] Brabazon A., O’Neill M., Dempsey I. (2008). An Introduction to Evolutionary Computation in Finance. IEEE Computational Intelligence Magazine, November, pp. 42-55, IEEE Press. [8] Bean Scripting Framework. http://jakarta.apache.org/bsf/ [9] Cebrian M., Alfonseca M., Ortega A. (2007). Automatic generation of benchmarks for plagiarism detection tools using grammatical evolution. GECCO ’07: Proceedings of the 9th annual conference on Genetic and evolutionary computation, Vol. 2, pp. 2253-2253, ACM Press. [10] Cleary R. (2005). Extending Grammatical Evolution with Attribute Grammars: An Application to Knapsack Problems, Masters Thesis, University of Limerick. Available from http://ncra.ucd.ie/ downloads/pub/thesisExtGEwithAGs-CRC.pdf [11] de la Puente A.O., Alfonso R.S., Moreno M.A. (2002). Automatic composition of music by means of grammatical evolution. Proceedings of the 2002 conference on APL, pp. 148-155, ACM Press. [12] Dempsey I. (2007). Grammatical Evolution in Dynamic Environments, PhD Thesis, University College Dublin. [13] Dempsey I., O’Neill M., Brabazon A. (2007). Constant Creation with Grammatical Evolution. International Journal of Innovative Computing and Applications, pp.23-38 Vol.1 No.1 [14] GEVA - Grammatical Evolution in Java. (2008). http://ncra.ucd.ie/ geva/ [15] GEVA user group. http://groups.google.com/group/geva Email: [email protected] [16] http://www.grammatical-evolution.org [17] Groovy. http://groovy.codehaus.org/ [18] Harper R., Blair A. (2005). A structure preserving crossover in Grammatical Evolution. In Proceedings of IEEE Congress on Evolutionary Computation, pp.2537-2544, IEEE Press. [19] Hemberg E., Gilligan C., O’Neill M., Brabazon A. (2007). A Grammatical Genetic Programming Approach to Modularity in Genetic Algorithms. In Ebner M., O’Neill M., Ekart A., Vanneschi L., and Esparcia Alcazar A. (eds.) EuroGP (Tenth European Conference on Genetic Programming), Valencia, Spain. Springer. 47 [20] Hemberg E., O’Neill M., Brabazon A. (2008). Altering Search Rates of the Meta and Solution Grammars in the mGGA. In LNCS 4971 O’Neill M., Vanneschi L., Gustafson S., Esparcia-Alcazar A.I., De Falco I., Della Cioppa A., Tarantino E. (Eds.) Proceedings of EuroGP 2008, pp.362373. Naples. Springer. [21] Hemberg E., O’Neill M., Brabazon A. (2008). Grammatical Bias and Building Blocks in Meta-Grammar Grammatical Evolution. In Proceedings of IEEE World Congress on Computational Intelligence, pp. , Hong Kong, IEEE Press. [22] JScheme http://jscheme.sourceforge.net/jscheme/main.html. [23] Karpuzcu U.R. (2005). Automatic Verilog Code Generation through Grammatical Evolution. In Proceedings of Genetic and Evolutionary Computation Conference (GECCO2005) workshop program, pp. 394397, ACM Press. [24] Lewin B. (2000). Genes VII. Oxford University Press. [25] Moore J.M., Hahn L.W. (2003). Petri net modeling of high-order genetic systems using grammatical evolution. BioSystems, 72(1-2), pp.177-186. [26] Murphy J.E., Carr H., O’Neill M. (2008). Grammatical Evolution for Gait Retargeting. In Proceedings of Sixth Theory and Practice of Computer Graphics 2008 Conference TPCG08 Eurographics. University of Manchester, UK. [27] O’Neill, M. (2007). COMP30290 Natural Computing. http://ncra. ucd.ie/COMP30290/ [28] O’Neill, M. (2001). Automatic Programming in an Arbitrary Language: Evolving Programs in Grammatical Evolution. PhD thesis, University of Limerick. [29] O’Neill, M., Ryan, C. (2001). Grammatical Evolution, IEEE Trans. Evolutionary Computation. 2001. [30] O’Neill, M., Ryan, C. (2003). Grammatical Evolution: Evolutionary Automatic Programming in an Arbitrary Language. Kluwer Academic Publishers. [31] O’Neill, M., Brabazon, A. (2005). Recent Adventures in Grammatical Evolution. In Proceedings of CMS 2005 Computer Methods and Systems. Vol.1, pp. 245-253, November 2005, Krakow, Poland. [32] O’Neill, M. and Brabazon, A. (2006). Grammatical Swarm: The Generation of Programs by Social Programming. Natural Computing, pp. 443-462 Vol.5 No.4 48 [33] O’Neill, M. and Brabazon, A. (2006). Grammatical Differential Evolution. International Conference on Artificial Intelligence (ICAI’06), pp. 231-236 CSEA Press Las Vegas, Nevada. [34] O’Neill, M., Brabazon, A. (2008). Evolving a Logo Design using Lindenmayer Systems, Postscript and Grammatical Evolution. In Proceedings of the IEEE World Congress on Evolutionary Computation, pp. 37883794. Hong Kong, 1-6 June 2008. IEEE Press. [35] O’Neill M., Brabazon A., Hemberg E. (2008). Subtree Deactivation Control with Grammatical Genetic Programming. In Proceedings of IEEE World Congress on Computational Intelligence, pp. , Hong Kong, IEEE Press. [36] O’Reilly U-M., Hemberg M. (2007). Integrating generative growth and evolutionary computation for form exploration. Genetic Programming and Evolvable Machines, 8(2), pp.163-186. [37] Prusinkiewicz, P. (1990). The Algorithmic Beauty of Plants. SpringerVerlag. Also available from http://algorithmicbotany.org/papers/ #abop. [38] Poli, R., Langdon, W.B., McPhee, N.F. (2008). A field guide to genetic programming. Published via http://lulu.com and freely available at http://www.gp-field-guide.org.uk. [39] Ryan, C., Collins, J.J., O’Neill, M. (1998). Grammatical Evolution: Evolving Programs for an Arbitrary Language. Proc. of the First European Workshop on GP, pp. 83-95, Springer-Verlag. [40] Tsoulos I.G., Lagaris I.E. (2006). Solving differential equations with genetic programming. Genetic Programming and Evolvable Machines, 7(1), pp. 33-54. 49