From whatever I have seen, some of the code in the scientific domain is really ugly. Especially for GA and GEP, people write their own hacks, which takes effort and yields untested, non-modular code which is like a cipher for everyone except the author. Maintenance and extension become huge problems.
Good coding is not just a technique. It is a philosophy which can answer many questions.
Besides, there are immediate, earthly benefits arising out of good, systematic, modular design
Amiba should be written very systematically, using the best practices of object oriented programming. In particular, it should make full use of the power of Java and related tools.
The grammar (encoding) used to build individuals should be separated from the general process of evolution. One should be able to plug-in any well-defined grammar and the evolution should perform its task.
So Amiba will have 3 parts
The evolution engine with genetic operators like mutation, transposition and recombination
The grammar (encoding) used to build individuals. Some typical grammars will be bundled with Amiba, along with the basic structure required to create new ones
A mechanism to feed fitness cases for training as well as testing purposes
Scope for Amiba-1.0
Create a more or less complete class structure to support systematic use and extension of Amiba
Create ScientificGrammar and GraphGrammar implementations to demonstrate the point
ScientificGrammar refers to a grammar that operates on class Double and implements the basic operations found on a scientific calculator. So a chromosome will be made-up of operators like addition and square root and terminals that represent Double objects
GraphGrammar refers to a grammar that operates on graphs and implements basic graph operations like dffsddd. We use JGraphT library for this purpose.
Create a basic, reasonably good XML-based configuration structure. More Refinement will only be possible in future versions, after some use. This XML configuration should encode all the parameters needed for GEP
Do performance engineering
Incorporate constants and parameters?
Add more grammars
More improvements according to the the feedback and discovered bugs
Something About The Design
The Framework and the Plug-ins
Amiba is designed as a rather generic framework accompanied by the most common plug-ins. This gives readymade all the common functionality while ensuring the freedom to implement your own specialized functionality. For example, a GeneGrammar represents a grammar for a gene. An implementation in the form of ScientificGrammar is provided. This implementation deals with the simple operations of a scientific calculator. You also have the freedom of implementing GeneGrammar for a completely different set of operators that may operate on objects other than numbers and that may have n number of operands.
This philosophy has been followed throughout. Generic behavior is defined through interfaces and abstract classes. The implementations of the most common use cases are bundled with this structure.
The choices made while using Amiba will be dictated by
The problem domain. For example, what kind of grammar to use
The problem itself. For example, the selection rate, the replication rate, population size etc.
Case 1: You are happy with the bundled grammars like ScientificGrammar and GraphGrammar
Many of the cases are expected to fall in this category. You only have to give method calls as shown in the example code. Just specify your configuration options in AmibaConfig.xml.
Case 2: You want to implement your own grammar
This takes a bit more effort. The new implementation is to be made available through abstract factory pattern. So you have to implement AmibaFactory and make sure it yields your implementation of FitnessCaseLoader and GeneGrammar.
You need to implement FitnessCaseLoader because how a fitness case is described depends on what kind of terminals you are going to use. You will need to define a structure for your fitness case and parse that structure through FitnessCaseLoader.load()
To implement GeneGrammar
Specify the parser using JavaCC-JJTree and generate related classes
Make sure the root node of the AST implements GEPRootNode
Provide the visitor implementation that will traverse the AST and evaluate it
Note that we are using visitor pattern for AST traversal. You don’t have to know JavaCC inside out. In fact, the ScientificParser.jjt file can be reused with minor modifications as long as you are dealing with a prefix grammar having operators and operands! That is the beauty of visitor pattern. The specific actions to be taken at each node go into the visitor implementation. You can have a look at the bundled implementations to understand this process better.