Evolving Efficient Recursive Sorting Algorithms - CiteSeerX

12 downloads 0 Views 236KB Size Report
Department of Computer Science. University of Essex, Colchester CO4 3SQ, UK [email protected]. Abstract—Object Oriented Genetic Programming (OOGP).
Evolving Efficient Recursive Sorting Algorithms Alexandros Agapitos Department of Computer Science University of Essex, Colchester CO4 3SQ, UK [email protected]

Abstract— Object Oriented Genetic Programming (OOGP) is applied to the task of evolving general recursive sorting algorithms. We studied the effects of language primitives and fitness functions on the success of the evolutionary process. For language primitives, these were the methods of a simple list processing package. Five different fitness functions based on sequence disorder were evaluated. The time complexity of the successfully evolved algorithms was measured experimentally in terms of the number of method invocations made, and for the best evolved individuals this was best approximated as O(n × log(n)). This is the first time that sorting algorithms of this complexity have been evolved.

I. I NTRODUCTION Evolving algorithms with non-trivial control structures is a significant challenge for Genetic Programming (GP). Control regimes, such as conditionals, iteration and recursion, are sufficient to make the GP paradigm Turing-complete, but this does not make a system inherently scalable. On the other hand, object oriented programming is the best way the software industry knows of creating scalable, manageable software. This is essential when evolving solutions to realworld problems where the data requirements are mapped to complex data structures that need to be manipulated via application-dependent operations, or where complex behavior needs to be abstracted in the form of procedures that have sophisticated flow of control. A significant amount of research [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14] has been devoted towards the direction of emergent computational complexity in GP, either in the form of iteration or recursion. Sorting is the computational process of rearranging the items of a given sequence into ascending or descending order [15]. It has a long history in computer science and is a process that requires considerably complex control structures and algorithmic sophistication. There is a plethora of solutions to this problem domain - some are simple and intuitive, while others are complicated but of greater utility and efficiency. Sorting algorithms fall into two classes of time complexity, specifically, O(n2 ) and O(n × log(n)). The quadratic algorithms are usually expressed iteratively, whereas the divide-and-conquer nature of the more efficient O(n × log(n)) algorithms leads more naturally to recursive expressions. The sorting problem has attracted a great deal of research, due to its ubiquity, and due to the challenge of solving it efficiently. The first O(n × log(n)) sorting algorithms were merge sort in 1945 by von Neumann, Shell’s

Simon M. Lucas Department of Computer Science University of Essex, Colchester CO4 3SQ, UK [email protected]

diminishing increment sort in 1959 and Hoare’s quicksort in 1962 [15]. This paper presents work on evolving general recursive sorting algorithms within an Object Oriented Genetic Programming (OOGP) system [13]. Sorting, as described above, is clearly an open-ended problem for GP since the evolved hypothesis will have to rearrange the comparable elements of any sequence of arbitrary length into order. While previous research on the evolution of iterative sorting has showed some promise, the evolution of recursive sorting algorithms has received no attention from the evolutionary computation community. This is a significant challenge, and in this paper we show that it can be addressed with an appropriate problem setup. The authors have previously showed [13] that it is possible to routinely and reliably evolve a range of general recursive functions within an OOGP system. The recursion mechanism used is general and in-line with that of conventional programming; recursive behavior happens when a function calls itself (perhaps as a result of intermediate function calls). Each evolved method in our OOGP system looks much like a Java method, with a declaration (signature: return type and parameter types) and an implementation, which is an expression tree evaluated with the arguments bound to the parameters. The expressions are strongly typed, and may also make calls to any specified methods in the Java API. The selection of primitives for constructing and representing hypotheses is very crucial to the success of an EA. Different representations (and their associated diversification operators) structure the program space in different ways, and this can have important implications for how evolvable the representations are in that space. The idea is that careful design of language constructs should enable the evolution of programs with more complex behaviors. This idea is fundamentally simple: to work in the programming space most appropriate to the problem under consideration. On an intuitive level, the higher the complexity encapsulated in the primitive alphabet, the more expanded the class of problems that can be addressed. Figure 1 shows a Java version of Quicksort. Note that special list-based classes and methods have been defined (using standard Java programming techniques) to enable this style of solution, including a higher-order function called filter. This version of filter was conceived with Quicksort in mind, but more general versions are of course possible. CList is a list of Comparable items, and GreaterThan and NotGreaterThan are predicates that implement the

static CList sort(CList l) throws Exception { if(l == null){ return l; } else { return CList.append( sort(filter(l.tail(), GraterThan, l.head())), CList.cons(l.head(), (sort(filter(l.tail(), NotGreaterThan, l.head()))))); } } static CList filter(CList l, MyComp comp, Comparable x) throws Exception { if(l == null){ return l; } else { if(comp.compare(x, l.head())) { return CList.cons(l.head(), filter(l.tail(), comp, x)); } else { return filter(l.tail(), comp, x); } } } Fig. 1.

Quicksort coded in Java, but using a functional style of programming

MyComp comparator interface. The point is that given these built-in operators, it seems quite feasible that algorithms such as Quicksort might be evolved. Contrast this with an imperative style implementation of Quicksort based on manipulating values in arrays. Intuitively, because there are so many dependencies between the index variables used to access the arrays in various parts of the program, it seems that this style of implementation would be very much harder to evolve. However, this is a highly contentious issue, and there are those in the EC field who believe that messy style implementations are fundamentally more evolvable. The remainder of the paper is organized as follows: we next provide a literature survey on the evolution of sorting algorithms. Then the fitness functions used to guide the evolutionary search are described. We then proceed to describe the experimental context: primitive terminal and non-terminal sets, evolutionary algorithm’s control parameters, followed by a section that details and discusses the experimental results, and the computational effort involved. We then discuss our investigation of the implications of the language constructs in the process of evolution. Two evolved algorithms are subsequently evaluated for time complexity using empirical data averaged over several runs against random data sets of predetermined size. In an attempt to find correlations to the computational effort presented previously, the landscapes resulting from different primitive constructs and fitness functions are analyzed via the examination of adaptive walks. Finally, conclusions are drawn. II. P REVIOUS WORK ON THE EVOLUTION OF SORTING ALGORITHMS

A literature review on sorting algorithm evolution revealed a limited repertoire of attempts in this problem domain. The evolved algorithms have been limited in the class of O(n2 ) such that bubble sort and insertion sort being evolved. Kinnear [16], [17] evolved general iterative sorting algorithms, mainly of bubble sort’s simplicity. He investigated

the relative probability of success and the difficulty resulting from varying the primitive terminal and non-terminal elements. The primitive alphabet contained elements that could result in an exchange-oriented sorting strategy. Primitive functions were defined for swapping sequence elements, comparing elements in specified sequence index values, incrementing and decrementing arithmetic variables. Control functions contained conditionals and a bounded iteration construct. The fitness function was based on the number of inversions, a measure of sequence disorder [15]. It considered the addition of a linear parsimony function in order to discourage the individuals’ increasing size as well as a disorder penalty, in the case where the remaining disorder was greater than the initial disorder. O’Reilly and Oppacher [18], [19] also investigated ways of evolving iterative sorting algorithms. Their first attempt [18] failed to produce a 100% correct individual. The representational constructs and fitness function used were different than those used in Kinnear’s experiments. Specifically, primitive functions and control structures included decrementing a variable, accessing indexed sequence elements, swapping adjacent sequence elements, bounded looping, and conditional. The fitness function counted the number of out-ofplace items. Their second attempt [19] yielded a successful outcome. It considered different primitive constructs and two fitness functions; the first fitness function was the same as in [18] whereas the second was based on permutation order [15], the count for each sequence element of the smaller elements that follow it. The primitive setup used the same bounded iteration and element swapping constructs and added two functions: First-Wrong and Next-Lowest that return the index of the first element that is out of order and the index of the smallest element after a particular indexed position respectively. Abbott [20] used an Object Oriented Genetic Programming system to generate an insertion sort of quadratic complexity.

He defined a List class of Integer object as a subclass of Java’s ArrayList class. His system operated in a bigger program space by providing all methods declared in ArrayList as primitives for constructing hypotheses. Besides the standard API methods, two additional methods were declared: iterate() and insertAsc(). The former dictates the bounded iteration behavior, while the latter inserts its argument before the first element of the List that is greater than or equal to the argument. Using this alphabet it was quite straightforward for an insertion sort to emerge. Although the set of primitive functions is sufficiently capable of expressing both an exchange- and insertion-oriented sorting recipe, Abbott does not report whether attempts were made to generate a sort program of bubble sort’s structure. The most recent attempt to the evolution of sorting algorithms is presented in the work of Spector et al [1] with their PushGP system. They used primitives along the lines of earlier investigations: swapping and comparing indexed elements, getting the list length, accessing list elements. The Push3 programming language offers a variety of explicit iteration instructions but also allows for the evolution of novel control manipulation structures. They evolved an O(n2 ) general sorting algorithm and suggested an efficiency component addition to the fitness function as a precursor to the evolution of ingenious O(n × log(n)) algorithms, though they report no experiments towards that direction. III. F ITNESS F UNCTIONS The fitness function is the driving force behind an evolutionary algorithm. The choice of fitness function can play a critical part in the success of a given run. In this work, we consider fitness functions based on five different sequence disorder measures. This section proceeds as follows: we first familiarize the reader with two key concepts of sequence disorder, namely, inversions and runs. We then proceed to discuss potential shortcomings of the fitness functions used in previous research and to present the ones employed in this study. Let a1 a2 ...an be a permutation of the set 1, 2, ..., n. The pair (ai , aj ) is called an inversion [15] of the permutation if and only if i < j and ai > aj . Inversion pairs represent pairs of sequence elements that are out-of-order, so that a completely sorted sequence is a permutation with no inversions. Runs [15] is another measure of the randomness of a sequence. Runs are determined by placing a vertical line at both ends of a permutation a1 a2 ...an and also between aj and aj+1 whenever aj > aj+1 . The number of resulting segments specifies the number of runs in the permutation. The concept of runs is important to the study of sorting algorithms because they represent sorted segments of data. Kinnear calculated the fitness of an individual based on the number of inversions remaining after its evaluation. Although the number of inversions is an important measure of disorder it does not capture all types of disorder. For example consider the sequence: W1 = hbn/2c + 1, bn/2c + 2, ..., n, 1, ..., bn/2ci. It has a quadratic number of inversions

although it consists of two ascending runs, therefore, it is nearly sorted not in a sense captured by inversions. O’Reilly and Oppacher based their fitness function on the number of out-of-place elements. For a yet-to-be-evolved program to be rewarded for a partially correct behavior there need to exist elements in their correct position in the sequence. Since for most fitness cases a partially correct individual will succeed in minimizing the sequence’s disorder (in terms of elements’ positional distances between sorted and induced sequences) rather than placing certain elements in their correct position, this individual would not have been rewarded higher than a completely erroneous individual. The fitness functions used in this study are described below. These objective measures take the form of error; the lower the numerical value the better the performance. The raw fitness Fraw of a hypothesis h over a training set T of size n is induced in several steps. First the sequence disorder SDis (i) of a training case i, based on different measures detailed below, is calculated. The provisional fitness Fprov (i) of a hypothesis h for a training case i is determined by adding an element incompatibility penalty Pinc in order to penalize algorithms that resulted in shorter or longer sequences than those originally provided via the fitness cases. Pinc (i) of a training case i is given by the absolute difference of the lengths of the target and induced lists respectively. Its value is given by,

Pinc (i) = |Length(targeti ) − Length(inducedi )|

Fprov (i) = SDis (i) + Pinc (i)

(1)

(2)

Finally, the actual Fraw (h) is calculated using Equation 3, n X 1− i=1

1 2Fprov i

(3) n where Fprov is the provisional fitness of the hypothesis h for the training case i and n is the size of the training set T . Note that Fraw is adjusted within the range of {0.0, . . . , 1.0}. We intentionally fail to consider a parsimony pressure coefficient as it has been shown that it can significantly degrade the average performance of an EA. Future work will adopt more stringent measures against bloat. SDis , appearing in Equation 2, is masqueraded under the following measures. Mean Inversion Distance (MID): In terms of the disorder it represents, the significance of a disorder pair lies in the distance between its constituent elements. One measure of this kind of disorder is defined as the largest distance determined by an inversion [21], [22]. The sequence’s inversion pairs are determined and MID is based on the average, over the inversion set, of the absolute distances determined by the inversions. Mean Sorted Position Distance (MSPD): One important Fraw (h) =

consideration is the difference between local disorder and global disorder. For example [22], a book in a library will be easier to find if it is close to its correct position. The measure that evaluates this type of disorder is defined as the largest distance an element must travel in order to reach its sorted position [21], [22]. Here, this is calculated by averaging over the list’s length, of the absolute distance determined by the sorted and current position of all out-of-place elements. Minimum Number of Exchanges (MNE): Of primary interest to the measures of sequence disorder is the number of operations (exchanges) required to rearrange a sequence into sorted order. This measure is defined as the minimum number of exchanges required [23]. MNE is calculated for each induced list. Number of Elements to Remove (REM): One possible reason for disorder is the insertion of incorrect elements. REM is defined as the minimum number of elements that must be removed to obtain a sorted sequence [15]. Alternatively REM can be defined as |X| − LAS(X) where LAS(X) is the length of the largest ascending subsequence, that is, LAS(X) = M AX{t|∃i(1), i(2), ..., i(t)|1 ≤ i(1) ≤ i(2) ≤ ... ≤ i(t) ≤ n and xi(1) < ... < xi(t) }. Number of Step Downs (NSD): Recall from above that runs is the number of sorted segments of data. NSD measures disorder in terms of number of ascending runs. In order to make the function zero for a sequence without disorder, NSD has been defined [22] as the number of boundaries between runs. These boundaries are called step-downs [15], at which a smaller sequence element follows a larger one. IV. E XPERIMENTAL C ONTEXT We study the effect of two different primitive set configurations as well as five different fitness functions on evolving general and efficient recursive sorting algorithms. The first configuration Sort-Filter includes the filter method defined in Figure 1 as a built-in primitive. We appreciate the relative importance of this operator and we wish to evolve it separately rather than use it as given. Once this building block is evolved we can then proceed and experiment with evolving sorting algorithms. The second configuration Sort-ADF does not consider the filter method as a built-in primitive and instead uses Koza’s Automatically Defined Function (ADF) approach to co-evolve both the sorting algorithm and the filter construct. Before applying the ADF methodology it is necessary to specify the architecture of the structures undergoing adaptation. Two dominant approaches: (a) static determination of the overall architecture (number of function-defining branches that are to be available, number of arguments possessed by each ADF, hierarchical references if the program contains more than one ADFs), (b) allowing the architecture to be subject to evolutionary modification. We follow the first approach by specifying the signature of the filter method, presented in Figure 1. The evolving individual is comprised of one result-producing-branch (RPB) and one functiondefining-branch (FDB). Both branches allow recursive calls to themselves and RPB is also allowed to invoke FDB. Thus,

TABLE I P RIMITIVE ELEMENTS FOR EVOLVING SORTING ALGORITHMS Method Head Tail Append Cons Compare EqualTo Filter Control flow IF-Then-Else Terminal Parameter[0] Parameter[1] Parameter[2] Const: GreaterThan Const: NotGreaterThan Const: null

Method set Argument(s) type CList CList CList, CList Object, Object Comparable, Comparable Object, Object CList, MyComp, Comparable Conditional Argument(s) type Boolean, CList, CList Terminal set Value new GreaterThan() new NotGreaterThan() null

Return type Comparable CList CList CList Boolean Boolean CList Return type CList Type CList MyComp Comparable MyComp MyComp Object

we make a reference of FDB available in the set of primitive constructs for RPB. The experiments were performed using OOGP [13], a Java-based Object Oriented Genetic Programming research system capable of evolving OO method implementations that match a specified interface. Our hypothesis representation was based on a general-purpose set of list-processing operations. These operations reside in the programming space of potential solutions to the problem at hand. For the sorting domain, this is defined as the space of sequences of comparable items. Table I presents the primitive language constructs. Sort-Filter configuration used the entirety of terminal and non-terminal primitives defined in Table I. SortADF configuration (both RPB and FDB) used the same primitive setup as Sort-Filter except of the filter method. As mentioned above RPB was also able to invoke FDB. Importantly, OOGP’s representation of recursion is generic and in-line with conventional programming’s implementation of recursive calls [13]. It makes no distinction between builtin methods and the evolved method, thus making the evolved method’s reference available to the method set serving as the alphabet for constructing the adaptive tree structures. Control parameters, unless otherwise stated, are the same for both configurations. These were specified as follows. Population size was set to 10, 000 and 12, 000 individuals for Sort-Filter and Sort-ADF respectively, and the number of generations was fixed to 100. It seemed unnecessary to extend the number of generations since the runs of Sort-Filter and Sort-ADF tended to stagnate after approximately 50 and 45 generations respectively. In order to enforce diversity in the initial random generation, ramped half-and-half was used as a tree generation method (no uniqueness requirement) with maximum initial depth set to 4 and maximum depth produced by the variation operators set to 10. Tournament selection (tournament size of 3) along with elitism (1%) was used as the selection mechanism. The distribution of selection

of crossover points was set to 90% probability of selecting interior nodes (uniformly) and 10% probability of selecting a leaf node. Standard variation operators of strongly-typed crossover (XO), macro-mutation (MM — substituting a node in the tree with an entire randomly generated subtree with the same return type) were used as in [13]. The search regime employed to explore the space of recursive programs embodied 99% XO combined with 1% MM. The training cases used to drive evolution consisted of 10 random lists of 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 unique elements respectively. Elements were randomly chosen from the range of {0, . . . , 250}. Evolution terminated if the maximum number of generations was reached or an individual reproduced successfully the training set outputs. Test sets measured the ability of an evolved solution to generalize to unseen data and recognized the success of a run. Sorting is an open-ended problem and testing cannot guarantee the generality of a sorting algorithm. Testing in this problem domain can increase our confidence in a high level of adequacy. Test cases for generality consisted of 200 random lists with a maximum random length of 100. Elements were drawn from within the same range as above with no uniqueness requirement. Successfully evolved individuals were subsequently tested correct against random lists of up to 100, 000 elements in order to be evaluated for time complexity. It is noteworthy that the general evolved solutions make no reference to the length of the input sequence. In order to avoid the problem caused by non-terminating recursive structures [13] we limited the recursive calls to between 25 and 10, 500. The upper bound of 10, 500 was chosen to be slightly larger than the largest number of recursive calls required by our hand-coded implementation of the most recursively expensive configuration, Sort-ADF. By limiting the recursive calls in this way, we may have been providing a very weak form of guidance to the evolutionary algorithm, but this was done simply to place a reasonable limit on the run time. When limited in this way, each single run of the EA still took several hours. There is another point of practical interest, raised during experimentation. The set of primitive constructs used in hypothesis representation can facilitate the emergence of programs that return a list of greater size than the one passed as a parameter. Consider for example a program that accepts a list as input and returns the concatenation of the argument list with itself. The situation is worsened if recursion causes its execution to be repeated numerous times. Clearly, the evaluation of such an individual is very expensive in terms of memory resources and can degrade the performance of the system up to the point of collapse. There is a need to discourage the evolution of solutions that exploit this characteristic. We designed a special monitor class called ArgumentMonitor. The monitor poses a limit to the length of the argument list during recursive invocations. When a program reaches the execution limit (measured in terms of recursive calls) or an argument list of size greater than the one allowed is passed as an argument, evaluation is abandoned and the individual

TABLE II S UMMARY OF RESULTS FOR Sort-Filter AND Sort-ADF CONFIGURATIONS ( BOLD FACE INDICATES BEST PERFORMANCE ON A GIVEN PROBLEM , STANDARD ERRORS IN PARENTHESES FOR PROB . OF SUCCESS ) Fitness func. MID MSPD MNE REM NSD Fitness func. MID MSPD MNE REM NSD

Sort-Filter Prob. Success(%) Min. I(M,i,z) 46 (2.5) 3,360,000 43(2.5) 3, 960, 000 31(2.1) 6, 120, 000 26(1.9) 7, 140, 000 20(1.6) 10, 340, 000 Sort-ADF Prob. success(%) Min. I(M,i,z) 16 (1.3) 13,224,000 11(1.0) 21, 120, 000 14 (1.2) 16,368,000 5(0.5) 43, 200, 000 7(0.7) 33, 300, 000

Fitness eval. 33,600,000 39, 600, 000 61, 200, 000 71, 400, 000 103, 400, 000 Fitness eval. 132,240,000 211, 200, 000 163,680,000 432, 000, 000 333, 000, 000

is assigned the maximum error. V. E VALUATING THE GENERALITY OF THE EXPERIMENTAL SETUP

On a practical level we want to ensure that the experimental setup is general and that by no means biasing the convergence towards sorting algorithms. For this purpose we are fixing two supplementary experiments to evaluate its generality. Our aim is to evolve different recursive functions that reside in the same programming space as the solution to the sorting problem. The target functions were chosen to be those of (a) reversing a list and (b) duplicating each element in a list. These recursive functions have the same signature (parameters and return value) as the sort method of Figure 1. The idea is that by using the same primitive terminal and non-terminal sets but varying the fitness function and the training data we can lead the system to learn different target functions. Experiments used a population of 1, 000 individuals and 50 generations. For variation operators, the same probabilistic setup was used as above. The fitness function was based on the sum of the positional distances between the same elements of the induced list and the target list, averaged over the length of the target list. Training and test set sizes were defined as above. For the evolution of the list reversal function we found that the computational effort I(M,i,z) reaches a minimum value of 110, 000 individuals in generation 0. Given that 10 fitness cases were used during training, the number of fitness evaluations required is 1, 100, 000. Accordingly for the list element duplication function we found that I(M,i,z) reaches a minimum value of 400, 000 by generation 9. The number of fitness evaluations required is 4, 000, 000. VI. R ESULTS We performed 100 independent runs on each fitness function of each configuration in order to get statistically meaningful results. The computational effort I(M,i,z) was computed in the standard way. A summary of the computational effort, sufficient to yield a solution to the considered

Fig. 2. Comparison of cumulative probability of success of different fitness functions for Sort-Filter configuration

Fig. 4. Performance curves for the filter problem with a population size M = 10,000 for generations 0 through 50

Fig. 3. Comparison of cumulative probability of success of different fitness functions for Sort-ADF configuration

Fig. 5. Graph plotting the input list size against method invocations required to perform the sorting. The legend presents the coefficients for minimizing the mean square error between actual F (n) and estimated invocations

problem with 99% confidence, is illustrated in Table II. The standard error estimates derive from treating a successful outcome as the result of flipping a biased coin, and can be used to judge the statistical significance of the differences (there is a greater than 99% chance that the true probability of success lies within 3 standard errors of the estimate). Figures 2 and 3 present the cumulative probability of success resulting from the five different fitness functions for SortFilter and Sort-ADF configurations respectively. Figure 4 shows, for a population size M of 10, 000 and for generations 0 to 50, the performance curves showing P(M,i) and I(M,i,z) for the filter problem. Note that for this problem we used the same control parameters as those reported in Section IV for Sort-Filter configuration. We observe that I(M,i,z) reaches a minimum value of 240, 000 at generation 11. Given that 10 fitness cases are used to guide learning, the number of fitness evaluations to be processed is 2, 400, 000. Figures 6 and 7 illustrate two sample evolved sorting algorithms under different configurations. Note that we show only the simplified versions; the evolved versions prior to simplification tend to be bloated to maximum tree depth. This may have been avoidable had we used some form of parsimony pressure.

VII. D ISCUSSION This work investigates the effects of language design on evolving implementations of efficient sorting algorithms as well as the proficiency of different fitness functions in traversing an evolutionary pathway through the fitness landscape. Empirical data suggest that the complexity encapsulated in the primitive operations has a significant impact on evolutionary learning. Domain-specific operations are useful but may entail the risk of making the target problem much easier. This is also a criticism leveled in GP as a general machine learning method: is it the adaptive search algorithm on the human expertise supplying domain-specific operations? In answering this question one might need to consider the class of problems being addressed using these specially built language constructs. Indeed, on the smallscale, these constructs may be rendering the emergence of the target solution more likely since they result in a smaller search space, but may also facilitating the solution to a much harder problem than would otherwise be feasible. We believe that the application of the GP paradigm to real-world problems requires an evolutionary search in the programming

TABLE III R ESULTS FOR A DAPTIVE WALKS , AVERAGED OVER 2000 WALKS , MAXIMUM OF 30

NEIGHBORS CONSIDERED

Sort-Filter Fitness Function MID MSPD MNE REM NSD Fitness Function MID MSPD MNE REM NSD

Original Error min. mean 0.135162 0.531254 0.354771 0.794068 0.695313 0.933305 0.720313 0.94617 0.714063 0.903749 Original Error min. mean 0.249206 0.494841 0.528587 0.772414 0.739063 0.931631 0.699609 0.918972 0.6625 0.878709

Final Error min. mean 0.049004 0.281722 0.14482 0.612846 0.396875 0.851911 0.398438 0.827273 0.36875 0.807157 Sort-ADF Final Error max. min. mean 1 0.234096 0.259297 1 0.528587 0.545265 1 0.739063 0.758293 1 0.699609 0.722275 1 0.6625 0.681257 max. 1 1 1 1 1

(IF-Then-Else (Method: et Parameter[0] Constant: null ) (Method: tail) (Method: append (Method: cons (Evolved_Method (Method: filter (Method: tail) Object: GreaterThan (Method: head) ) ) (Method: head) ) (Evolved_Method (Method: filter (Method: tail) Object: NotGreaterThan (Method: head) )))) Fig. 6.

Sample simplified evolved sorting algorithm (Sort-Filter config.)

space most appropriate to the problem at hand. The design of special language constructs (like Filter) can greatly enhance the process of evolution. The limited range of realworld evolved solutions suggests that such an attempt is clearly worthwhile. Making GP scale up to larger systems is still a challenge, and the space in which we search is of fundamental importance. We need to stress the fact that we are operating in the programming space of sequences of comparable items, a space rather different than the one chosen in previous attempts (based on manipulating values in arrays). We argue that within this space the evolvability of sorting hypotheses can be significantly increased. VIII. T IME C OMPLEXITY OF E VOLVED A LGORITHMS This section evaluates the time complexity of the evolved sorting algorithms presented in Figures 6 and 7. Here, we evaluate efficiency in terms of the number of method invocations. Since the speed of the sort can vary greatly depending on the randomness of the data-sets (and also on

max. 1 1 1 1 1

Adaptive Walk Length min. mean max. 0 3.3705 15 0 2.156 8 0 1.8435 8 0 1.786 10 0 1.4315 9

max. 1 1 1 1 1

Adaptive Walk Length min. mean max. 0 1.711 8 0 1.5545 9 0 1.56 9 0 1.4765 9 0 1.4625 8

Evolved_Method (RPB): (IF-Then-Else (Method: et Parameter[0] Constant: null ) (Method: tail) (ADF[0] (Evolved_Method (Method: tail) ) Object: NotGreaterThan (Method: head) ) )

Fig. 7.

ADF[0]: (IF-Then-Else (Method: compare (Method: head) Parameter[2] ) (Method: cons (Method: head) (ADF[0] (Method: tail) Parameter[1] Parameter[2] ) ) (Method: cons Parameter[2] Parameter[0]))

Sample simplified evolved sorting algorithm (Sort-ADF config.)

CPU noise), accurate empirical results require several runs of the sort to be made and the results averaged together. The empirical data presented in Figure 5 is the average of a hundred runs against random input lists of predetermined length. We plot the size of the input list against method invocations required for the evolved algorithms to perform the sorting. The evolved algorithms of Figures 6 and 7 fall into O(n × log(n)) and O(n2 ) classes respectively. We also plot n, n2 and n × log(n) curves and present how these fit into the evolved ones. The coefficients presented in the legend of Figure 5 are those that minimize the mean squared error between actual F (n) and estimated method invocations. IX. A DAPTIVE WALKS Fitness landscapes provide a powerful tool for visualizing the difficulty of a problem. Experimental results indicated that specific measures, under the same primitive alphabet configuration, performed differently to the task of traversing a path to the target hypothesis. In an attempt to better interpret the results and determine correlations between observed performance and search heuristics used, we employ adaptive walks to analyze the structure of the landscapes resulting from the different objective functions.

Adaptive walks has been used in [24], showing good correlation with problem difficulty, over the entire range of problems examined. The mean walk length at the end of an adaptive walk on a landscape indicates the number of steps required to reach a local optimum. Intuitively, the longer the walk’s length the easier to search the landscape. We employed the same adaptive walk algorithm as the one described in [24]. Briefly, an initial random population is created in an analogous way to the creation of the initial population of OOGP. An individual is selected using random uniform selection and evaluated for fitness. Variation operators are being applied in order to examine the neighborhood of the individual. The selection of the variation operator is probabilistically biased towards applying XO (in which case a second individual is randomly selected) with a probability of 99% and MM with a probability of 1%. For our purposes here, neighbor is defined as a point one variation operator distant in the landscape. Every emergent neighbor is evaluated for fitness. The first one that is fitter than the initial parent is selected as the new parent and the process continues until no neighbor can be found with better fitness - a local optimum has been reached. Similarly to [24], we arbitrarily choose the number of 30 neighbors to consider, before designating the outcome of the run. The results from the adaptive walks are presented in their entirety in Table III. One can observe that for both configurations there exists strong correlation between the mean walk length and the probability of success reported in Table II. In each case the MID function has the highest mean walk length, and also the highest probability of success. Clearly the ability to sort within this setup is not exactly a needle-in-a-haystack problem that one might fear, though there are only on average a few variations made before the walk gets stuck in a local optima (nevertheless, with only 30 evaluations made before giving up, this does not necessarily indicate a local minimum).

[2] [3] [4] [5] [6] [7] [8] [9] [10]

[11] [12] [13]

[14] [15] [16]

X. C ONCLUSIONS The process of evolving general recursive sorting algorithms provided an interesting test-bed for assessing the impact of different primitive constructs and fitness functions on solving a challenging problem. This investigation has been another step towards emergent computational complexity in GP, and in a far more reaching scale, a step towards allowing the evolution of complex algorithms. The evolved sorting algorithms were reliably evolved from small samples of data and generalized perfectly. Their efficiency falls into the class of O(n × log(n)). We suggested the process of abstracting complexity into high-level primitive building blocks as a precursor to the application of GP paradigm to more complex real-world problems. Mean adaptive walk length showed positive correlation as to difficulty of learning in the sorting domain. R EFERENCES [1] L. Spector, J. Klein, and M. Keijzer, “The push3 execution stack and the evolution of control,” in GECCO ’05: Proceedings of the 2005

[17] [18] [19] [20]

[21] [22] [23] [24]

conference on Genetic and evolutionary computation. New York, NY, USA: ACM Press, 2005, pp. 1689–1696. L. Huelsbergen, “Learning recursive sequences via evolution of machine-language programs,” in Genetic Programming 1997: Proceedings of the Second Annual Conference. J. R. Koza, D. Andre, F. H. Bennett III, and M. Keane, Genetic Programming 3: Darwinian Invention and Problem Solving. Morgan Kaufman, Apr. 1999. C. Clack and T. Yu, “Performance enhanced genetic programming.” in Proceedings of the Sixth Conference on Evolutionary Programming, 1997. P. A. Whigham and R. I. McKay, “Genetic approaches to learning recursive relations,” in Progress in Evolutionary Computation. SpringerVerlag, 1995. M. L. Wong and K. S. Leung, “Evolving recursive functions for the even-parity problem using genetic programming,” in Advances in Genetic Programming 2. MIT Press, 1996. T. Yu and C. Clack, “Recursion, lambda abstractions and genetic programming,” in Genetic Programming 1998: Proceedings of the Third Annual Conference, 1998. M. J. Kochenderfer, “Evolving hierarchical and recursive teleo-reactive programs through genetic programming,” in Genetic Programming, Proceedings of EuroGP’2003, 2003. P. Nordin and W. Banzhaf, “Evolving turing-complete programs for a register machine with self-modifying code,” in Genetic Algorithms: Proceedings of the Sixth International Conference (ICGA95), 1995. M. Nishiguchi and Y. Fujimoto, “Evolutions of recursive programs with multi-niche genetic programming (mnGP),” in Proceedings of the 1998 IEEE World Congress on Computational Intelligence. Anchorage, Alaska, USA: IEEE Press, 5-9 May 1998, pp. 247–252. S. Brave, “Evolving recursive programs for tree search,” in Advances in Genetic Programming 2. MIT Press, 1996. E. Kirshenbaum, “Iteration over vectors in genetic programming,” HP Laboratories, Technical Report HPL-2001-327, Dec. 17 2001. A. Agapitos and S. M. Lucas, “Learning recursive functions with object oriented genetic programming,” in Proceedings of the 9th European Conference on Genetic Programming, ser. Lecture Notes in Computer Science, vol. 3905. Budapest, Hungary: Springer, 10 12 Apr. 2006, pp. 166–177. M. L. Wong, “Evolving recursive programs by using adaptive grammar based genetic programming,” Genetic Programming and Evolvable Machines, vol. 6, no. 4, pp. 421–455, Dec. 2005. D. E. Knuth, The art of computer programming, volume 3: (2nd ed.) sorting and searching. Redwood City, CA, USA: Addison Wesley Longman Publishing Co., Inc., 1998. K. E. Kinnear, Jr., “Generality and difficulty in genetic programming: Evolving a sort,” in Proceedings of the 5th International Conference on Genetic Algorithms, ICGA-93, S. Forrest, Ed. University of Illinois at Urbana-Champaign: Morgan Kaufmann, 17-21 July 1993, pp. 287– 294. ——, “Evolving a sort: Lessons in genetic programming,” in Proceedings of the 1993 International Conference on Neural Networks, vol. 2. San Francisco, USA: IEEE Press, 28 Mar.-1 Apr. 1993, pp. 881–888. U.-M. O’Reilly and F. Oppacher, “An experimental perspective on genetic programming,” in Parallel Problem Solving from Nature 2, 1992. ——, “A comparative analysis of GP,” in Advances in Genetic Programming 2, P. J. Angeline and K. E. Kinnear, Jr., Eds. Cambridge, MA, USA: MIT Press, 1996, ch. 2, pp. 23–44. R. Abbott, J. Guo, and B. Parviz, “Guided genetic programming,” in The 2003 International Conference on Machine Learning; Models, Technologies and Applications (MLMTA’03). las Vegas: CSREA Press, 23-26 June 2003. V. Estivill-Castro and D. Wood, “A new measure of presortedness,” Inf. Comput., vol. 83, no. 1, pp. 111–119, 1989. ——, “A survey of adaptive sorting algorithms,” ACM Comput. Surv., vol. 24, no. 4, pp. 441–476, 1992. H. Mannila, “Measures of presortedness and optimal sorting algorithms.” IEEE Trans. Computers, vol. 34, no. 4, pp. 318–325, 1985. K. E. Kinnear, Jr., “Fitness landscapes and difficulty in genetic programming,” in Proceedings of the 1994 IEEE World Conference on Computational Intelligence, vol. 1. Orlando, Florida, USA: IEEE Press, 27-29 June 1994, pp. 142–147.