Figure 1.8. A computer program in LISP (a) and its tree representation (b). Note that LISP operators precede their arguments, e.g., (a + b) is written as (+ a b).
Also worth mentioning is that, in GP, the genetic operators act directly on the parse tree and, although at first sight this might appear advantageous, it greatly limits this technique (it is impossible to make an orange tree produce mangos only by grafting and pruning). The genetic operators must be very carefully applied so that only valid structures are formed. For instance, in crossover, the most used and often only operator in GP, selected branches are exchanged between two parent trees to create offspring
(Figure 1.9). The idea behind its implementation was to exchange smaller, mathematically concise blocks in order to evolve more complex, hierarchical solutions composed of smaller building blocks. Effectively, GP crossover very much resembles the pruning and grafting of trees and, like these, has a very limited power. This kind of crossover was also devised because its implementation in LISP is trivial and the parse trees it creates are always legal LISP programs.
Figure 1.9. Tree crossover in genetic programming. The arrows indicate the crossover points.
The mutation operator in GP also differs from biological point mutations in order to guarantee the creation of syntactically correct LISP programs. The mutation operator selects a node in the parse tree and replaces the branch at that node by a randomly generated branch
(Figure 1.10). Again, the overall shape of the tree is not greatly changed by this kind of mutation, especially if lower nodes are preferentially chosen as mutation targets.
Figure 1.10. Tree mutation in genetic programming. The arrow indicates the mutation point. Note that the mutation operator creates a randomly generated branch at the mutation point.
Permutation is the third operator used in GP and the most conservative of the three. During permutation, the arguments of a randomly chosen function are randomly permuted
(Figure 1.11). In this case the overall shape of the tree remains unchanged.
Figure 1.11. Permutation in genetic programming. The arrow indicates the point of permutation. Note that the arguments of the permuted function changed places in the daughter tree. After permutation the shape of the tree remains unchanged.
Although J. Koza described these three operators as the basic GP operators, tree-specific crossover is practically the only genetic operator used in most GP applications. Consequently, no radically new material is introduced in the genetic pool of GP populations. Not surprisingly, huge populations of parse trees must be used so that all the necessary building blocks would be already present in the initial population in order to guarantee the discovery of a good solution solely by moving the initial building blocks around.
In summary, in GP the operators resemble more of a conscious mathematician than the blind way of nature. We will see that, in adaptive systems, the blind way is much more efficient and that systems like GP are highly constrained. For instance, the implementation of other operators in GP, like the equivalent of the high-performing point mutation
(Ferreira 2002a), is unproductive as most mutations result in syntactically incorrect structures
(Figure 1.12). Obviously, the implementation of other operators such as transposition or inversion raises similar difficulties and the search space in GP remains vastly unexplored.
Figure 1.12. Illustration of a hypothetical event of point mutation in genetic programming. Note that the daughter tree is an invalid structure.
Finally, due to the dual function of the parse trees (genotype and phenotype), GP is incapable of a simple, rudimentary expression: in all cases, the entire parse tree is the solution.