Scaling Genetic Programming for Source Code Modification

by   Brendan Cody-Kenny, et al.
Trinity College Dublin

In Search Based Software Engineering, Genetic Programming has been used for bug fixing, performance improvement and parallelisation of programs through the modification of source code. Where an evolutionary computation algorithm, such as Genetic Programming, is to be applied to similar code manipulation tasks, the complexity and size of source code for real-world software poses a scalability problem. To address this, we intend to inspect how the Software Engineering concepts of modularity, granularity and localisation of change can be reformulated as additional mechanisms within a Genetic Programming algorithm.



page 1

page 2

page 3

page 4


Code Obfuscation for the C/C++ Language

Obfuscation is the action of making something unintelligible. In softwar...

A Trillion Genetic Programming Instructions per Second

We summarise how a 3.0 GHz 16 core AVX512 computer can interpret the equ...

A Simple Approach for Handling Out-of-Vocabulary Identifiers in Deep Learning for Source Code

There is an emerging interest in the application of deep learning models...

Rethinking complexity for software code structures: A pioneering study on Linux kernel code repository

The recent progress of artificial intelligence(AI) has shown great poten...

gazel: Supporting Source Code Edits in Eye-Tracking Studies

Eye tracking tools are used in software engineering research to study va...

Towards Modal Software Engineering

In this paper we introduce the notion of Modal Software Engineering: aut...

Towards Using Data-Centric Approach for Better Code Representation Learning

Despite the recent trend of creating source code models and applying the...
This week in AI

Get the week's most popular data science and artificial intelligence research sent straight to your inbox every Saturday.

1 Introduction

Automating programming tasks has long been a goal in Computer Science. A current incarnation of this effort has been termed Search Based Software Engineering (SBSE) [9]

. SBSE seeks the automation of Software Engineering (SE) tasks by posing them as search problems. Various search algorithms which are classified by the term Evolutionary Computation (EC)

[7] have been used to perform software source code manipulation for various purposes [20]. Examples range from parallelisation [21] and generation of source code [2] to bug fixing [23].

An issue with the application of EC techniques to the modification of source code is designing algorithms that can scale with increased code size and complexity. Increased size and complexity increases the number of solutions that an algorithm must search through to find a solution. The algorithms are further impeded due to a “bloat” effect where the solutions produced generally expand in size as the search process progresses limiting the chances of finding the best solution.

Modularisation techniques have been proposed to scale EC techniques which allow the algorithm to define and reuse its own functions during its operation [14]. Another approach involves the use of static code analysis before the algorithm is applied to discover likely influential locations within code [24]

. The analysis produces a probability overlay over the source code which focuses the algorithms operations to likely useful locations.

Our approach draws on current SE principles which describe software as complex and constantly changing [26]. Many software architectures are developed to aid software change by adding different forms of modularity [5, 12, 10, 16]. Finer grained modularity and encapsulation facilitates localised modification and replacement of software elements by introducing more points for modification into the software [11]. While these software practices and architectures aid developers in building software for change, the modification of software source code remains a complex task.

An EC algorithm can be improved in efficiency and solution finding ability by localising computational modifications to where they are most likely needed [24]. Software can be modularised at various granularities as specified by a developer. This is generally driven by the recommendation for low coupling and high cohesion in software. Given a good modularisation at the right granularity, software changes can be implemented more easily. Making coarse changes would improve the scalability of the algorithm but may reduce the algorithms ability to find the best solution possible while making changes at a fine level, such as the language level instead of at the line of code, would allow a wider range of solutions to be generated but would slow down the algorithm.

Our position is that the SE principles of localisation and granularity of change have relevance for further improving the scalability of EC specifically for source code manipulation. Both of these concepts are enabled by modularisation of code. Instead of using EC algorithms to modularise software, we see the concept of modularisation as one that should be incorporated into EC algorithms themselves for the purposes of improving scalability[15]. Modularity is an SE concept which advocates that software should be structured to be understandable and modifiable [22]. It gives developers a general architecture for building software so that future modifications of the software can be made as efficiently as possible. We wish to incorporate the ability to modularise code for change within an algorithm which is suited and beneficial to how the algorithm operates.

We seek to apply modularisation to the problem of source code modification and ask:

  • Are the concepts of granularity and localisation beneficial when designing algorithms for source code modification?

The research goal that follows is to improve the scalability of an EC algorithm which modifies source code to change non-functional characteristics of software. Our work seeks to understand how localising change at varying granularity can improve the modification of source code using EC.

2 Related Work

An issue with generating software using EC methods is that size and complexity increases the size of the search space thereby reducing the probability of successfully finding the best solution [6, 4]. Within the EC literature this is posed as a scalability problem. When these techniques are applied to software generation it limits the applicability of the technique when considering large scale software systems. Although modification of existing software is an easier problem for EC techniques to solve than generation, it still suffers from the problem of scalability.

EC has been used to refactor software for improvement of software quality by use of a measure for understandability [18]. The metrics used in this and other work include software code quality measures for characteristics such as cohesion and coupling and has been termed Software Module Clustering [19]. The end goal of module clustering research is to produce software that is better modularised for developers. Our approach sees modularisation as a mechanism which can improve the scalability of an algorithm, regardless of what this form of modularisation may mean for developers.

Feldt applied algorithmic techniques to N-version programming [8]. The goal of N-version programming is to improve fault tolerance by producing multiple differing implementations of the same functionality. As the implementations generated must be entirely different from each other, there is no room for reuse of the original implementation for subsequent implementations. The software generation mechanism must generate software with the added stipulation that it must differ from the original which makes the problem harder.

The most recent example of automated approaches that operate directly on existing source code that can be considered “real-world”; is work on bug fixing [23]. Forrest and Weimer have used GP with multiple evolutionary runs to fix certain classes of bugs. This approach uses a line of code as the granularity of change. Static code analysis is used to localise modification of source code to areas that are likely to yield a fix. To further improve scalability of the technique, lines of code that are close in line number to these areas are more likely to be reused. The GP algorithm is applied multiple times indicating that this type of software change requires a relatively small number of changes to the code. Multiple runs are performed instead of a single longer run indicating that the rate of success of any one run is low. If a deeper or more widespread modification of the code were necessary, then multiple runs may not improve the likelihood of finding a solution. If a relatively small number of changes are sought to fix a particular bug, this poses the question as to how much of the code must be modified and what types of modifications are required for different classes of patches and other software characteristics changes? It is not known how the granularity of source code they choose for modification affects the class of bug fixes attainable. This may have a restricting affect on the bugs that can be corrected with this approach.

Our hypothesis is that this granularity has a positive effect on the scalability of the algorithm but restricts the number of possible solutions attainable by the algorithm. Further to this and evocative of our solution, it is not clear how dynamically varying granularity would impact scalability of the algorithm and range of modification, such as the performance improvement, for software. Forrest and Weimer’s results show that the algorithm works well for certain classes of bugs in code of varying size. While granularity and localisation have an impact on the scalability of the approach, the literature leaves some open questions around how each of these affect scalability individually and how they affect the solutions attainable.

Arcuri has developed a co-evolutionary EC framework to generate and improve source code [2]. The technique has been applied to the generation of source code for functional (bug fixing) and non-functional (performance improvement) purposes. Particular attention has been paid to testing which works well with co-evolution. In the co-evolutionary approach, test cases and programs form two separate populations with each ones usefulness measure being allocated by interaction with the other. The number of tests passed is used as a measure of how useful a generated program is. The number of generated programs that fail a test is used as a measure of how useful the test is. This is similar to Forrest and Weimer’s approach in that a series of true or false test cases are summed to give a measure of usefulness. Conversely to Forrest and Weimer, White, Arcuri et al. improve a non-functional characteristic, performance, of a smaller code-base using a finer granularity without any localisation [25]. The granularity used is at the language level in that the program is converted to an Abstract Syntax Tree which allows modification of individual language level constructs such as variables and control structures. This is the finest granularity allowed by the language. How this granularity affects the scalability and the range of change achievable by the algorithm is unclear. We believe that the finer granularity allows a wider range of solutions to be found by the algorithm for smaller code-bases. This work shows the applicability of the approach for modifying non-functional characteristics but does not inspect how the approach can scale to larger systems. Arcuri has also improved software performance while maintaining functionality through the use of multi-objective optimisation [3].

By comparing Arcuri with Forrest and Weimer’s work, the overall changes achievable are restricted to certain classes of bugs in one and a change in performance in the other. How granularity and localisation affects the algorithm is not directly inspected in either approach. Weimer’s research describes the approaches applicability in a number of open source software code bases of varying size. Arcuri’s work operates on a single model problem. While neither are conclusive or directly comparable, Weimer and Forrest’s work can be used as a rough indicator as to the approaches generality and scalability when dealing with large amounts of code. The range of change achievable, such as the measurable improvement in performance, is not comparable, nor can even a rough indicator be drawn from the results of these pieces of work.

From this discussion, and to the best of our knowledge, we can conclude that the effects of localisation and granularity of change have not been inspected for their impact on the possible trade-off between scalability and solution finding ability. We feel that both these concepts can be used to improve the operation of EC algorithms when applied to source code modification by allowing fine grained changes to be made in the right locations. Where coarse grained changes are suited to a particular portion of code, an algorithm should be allowed to operate at this granularity. This is expected to provide an efficient use of computational effort by focusing change in areas of the search space likely to contain good solutions without restricting the solution space through prohibiting possible solutions. This is our research focus.

3 Solution

Our solution would ideally be able to take as input the source code for a program, a range of test data and a fitness function for testing the performance of the program. The solution would return a modified version of the source code which has been improved on a scale as defined by the fitness function. This modified and improved version would be arrived at by the application of GP where the source code is used as a seed for the initial population. A compiled version of the initial source code along with the test data would be used as an oracle for maintaining program functionality. The GP system would progress by making changes to iterations of populations of source code programs using the fitness function to maintain a bias toward more improved programs.

The type of change in software that is sought is the modification of characteristics that could be termed non-functional. This is a rough designation of the types of changes sought and is an attempt to specify any change that has a relatively simple metric associated with it. Simple metrics generally relate to non-functional characteristics such as computation time required.

For the use of EC algorithms, a fitness function is required that can evaluate programs on a scale fine enough to indicate improvements after changes to a program. The scale should be a multi-valued monotonic metric where increases on the scale are linearly related to improvements in software characteristics. For functional behaviour, the generation of a scale which increases as the desired functionality improves is not trivial [13] and requires careful consideration and design in itself. For this reason, “non-functional” characteristics will be used. Our solution should be able to implement a different range of change in these characteristics than is possible with a static approach.

For small code segments, improvements can be made using the finest granularity as shown by Arcuri. As the code size increases, the chances of finding the same level of improvement is diminished. The finest granularity allows the largest number of possible solutions but does not scale well. Our concern is whether and how fine grained evolution can be scaled. Our hypothesis is that a focused variant of Genetic Programming via localisation of change may deliver the appropriate model. If our solution works as planned, we can automatically rewrite software to improve its performance. As the programs are evolved over time, the algorithm would be able to refine its focus within the code, making changes where needed.

Our approach to achieving this is to reuse the information generated when an offspring individual is produced from parent individuals. We believe that this information can be used to infer and refine location and granularity indicators for future modifications as the algorithm progresses. These indicators take the form of values associated with every location within each individual program. The values are used to bias the selection of locations for modification by the GP operators. The values make up a probability mask over an individual where any location may be chosen for modification but each location has a different probability of being subsequently modified. Allowing any change enables a larger solution space while avoiding the scalability problem this presents by guiding the GP algorithm toward likely solutions. These values are updated and passed along as the GP algorithm produces more individuals.

The most basic form of our solution is explained when considering a form of single point mutation which modifies a program by only one line of code. After this operation we have the original program, its fitness value and the modified version with its fitness value. Assuming a difference in fitness is seen between these two programs it can be inferred that mutation at or near that location is influential to the fitness. If a particular location is found to be influential, the associated value can be increased, improving this locations chance of being modified during future mutations. If no fitness difference is found, the value may not be changed or decreased slightly. If the change causes the program to not compile, the decrease may be larger.

As the algorithm progresses, a probabilistic mask of where change should and shouldn’t be performed over the source code would emerge. Generating a mask can be achieved by other means, such as static code analysis a la Weimer, but our argument is that the accuracy of this analysis for guiding change reduces as more modifications are made to the code. The more modifications are made to a program, the more it departs from the original and the less useful the static mask becomes.

We see useful change to software characteristics requiring a “deep” modification exemplified by an improved program having departed widely from the original. Our hypothesis is that the complexity of overall change attainable with multiple shorter runs using a static probability overlay is limited in comparison to a longer dynamically updating overlay. These two approaches would find a different range of solutions. If our hypothesis is correct, our solution should be able to make more complex changes to software. From this point of view, our work is addressing the complexity limitations of GP when applied to software modification.

Our approach is hoped to be more lightweight than repeated application of static analysis during a GP run as it reuses information generated during the GP run itself. It is also hoped that our approach may be more expressive, being able to guide GP more generally than static code analysis which would analyse code with regard to specific charactersitics such as cpu time.

Equipping the algorithm with multiple choices for granularity of change, e.g. block of code, single line of code, this solution could be extended to infer the most influential granularity to be used at a specific location. The algorithm could make an inference about the granularity of change that has caused a fitness change. This may be used to infer this granularity is a good one for making changes near this location.

Similar mechanisms have been described in the GP literature [17, 1] and are expected to be especially useful for use on software and further extension in this area. Following on from this, we will develop the solution so it can address granularity. Having a modularisation that is based on probabilities evokes the notion that it is a “fuzzy” modularisation which is not rigidly defined like a function and may look different every time a change is performed. Assuming we can experimentally validate how probabilities for change are allocated by the algorithm within individuals, a further inspection could be performed into how a probabilistic modularisation would compare with Automatically Defined Functions (ADF). The argument being that ADF’s are too restrictive, eliminating some possible solutions from the search space through their strict structure. A modularisation that has its boundaries only probabilistically defined would not restrict the solutions possible while improving scalability and guiding GP appropriately. This is less clearly defined as a solution and forms our future work.


  • [1] P. Angeline. Two self-adaptive crossover operations for genetic programming. 1995.
  • [2] A. Arcuri. Automatic software generation and improvement through search based techniques. PhD thesis, 2009.
  • [3] A. Arcuri, D. White, J. Clark, and X. Yao. Multi-objective improvement of software using co-evolution and smart seeding. Simulated Evolution and Learning, pages 61–70, 2008.
  • [4] W. Banzhaf and J. Miller. The challenge of complexity. Frontiers of Evolutionary Computation, pages 243–260, 2004.
  • [5] B. Cox. Object oriented programming. 1985.
  • [6] E. de Jong, R. Watson, and D. Thierens. On the complexity of hierarchical problem solving. In Proceedings of the 2005 conference on Genetic and evolutionary computation, pages 1201–1208. ACM, 2005.
  • [7] K. De Jong. Evolutionary computation: A unified approach, 2006.
  • [8] R. Feldt. Generating diverse software versions with genetic programming: an experimental study. In Software, IEE Proceedings-, volume 145, pages 228–236. IET, 1998.
  • [9] M. Harman, S. Mansouri, and Y. Zhang. Search based software engineering: A comprehensive analysis and review of trends techniques and applications. Department of Computer Science, King’s College London, Tech. Rep. TR-09-03, 2009.
  • [10] G. Heineman and W. Councill. Component-based software engineering: putting the pieces together. Addison-Wesley USA, 2001.
  • [11] C. Kästner, S. Apel, and M. Kuhlemann. Granularity in software product lines. In Proceedings of the 30th international conference on Software engineering, pages 311–320. ACM, 2008.
  • [12] G. Kiczales, J. Lamping, A. Mendhekar, C. Maeda, C. Lopes, J. Loingtier, and J. Irwin. Aspect-oriented programming. ECOOP Object-Oriented Programming, pages 220–242, 1997.
  • [13] K. Kinnear Jr. Generality and difficulty in genetic programming: Evolving a sort. In

    Proceedings of the Fifth International Conference on Genetic Algorithms

    , pages 287–294. Citeseer, 1993.
  • [14] J. Koza. Scalable learning in genetic programming using automatic function definition. MIT Press, 1994.
  • [15] J. Koza, D. Andre, F. Bennett III, and M. Keane. Use of automatically defined functions and architecture-altering operations in automated circuit synthesis with genetic programming. In Proceedings of the First Annual Conference on Genetic Programming, pages 132–140. MIT Press, 1996.
  • [16] B. Magableh and S. Barrett. Pcoms: A component model for building context-dependent applications. In Future Computing, Service Computation, Cognitive, Adaptive, Content, Patterns, 2009. Computation World, pages 44–48. IEEE, 2009.
  • [17] H. Majeed and C. Ryan. A less destructive, context-aware crossover operator for gp. Genetic Programming, pages 36–48, 2006.
  • [18] M. O’Keeffe and M. Cinnéide. Search-based refactoring: an empirical study. Journal of Software Maintenance and Evolution: Research and Practice, 20(5):345–364, 2008.
  • [19] K. Praditwong, M. Harman, and X. Yao. Software module clustering as a multi-objective search problem. Software Engineering, IEEE Transactions on, (99):1–1, 2009.
  • [20] O. Räihä. A survey on search-based software design. Computer Science Review, 4(4):203–249, 2010.
  • [21] C. Ryan. Automatic Re-engineering of Software Using Genetic Programming, volume 2 of Genetic Programming. Kluwer Academic Publishers, 1 Nov. 1999.
  • [22] K. Sullivan, W. Griswold, Y. Cai, and B. Hallen. The structure and value of modularity in software design. In ACM SIGSOFT Software Engineering Notes, volume 26, pages 99–108. ACM, 2001.
  • [23] W. Weimer, S. Forrest, C. Le Goues, and T. Nguyen. Automatic program repair with evolutionary computation. Communications of the ACM, 53(5):109–116, 2010.
  • [24] W. Weimer, T. Nguyen, C. Le Goues, and S. Forrest. Automatically finding patches using genetic programming. In Proceedings of the 31st International Conference on Software Engineering, pages 364–374. IEEE Computer Society, 2009.
  • [25] D. White, A. Arcuri, and J. Clark. Evolutionary improvement of programs. Evolutionary Computation, IEEE Transactions on, (99):1–24, 2011.
  • [26] L. Williams and A. Cockburn. Guest editors’ introduction: Agile software development: It’s about feedback and change. Computer, 36(6):39–43, 2003.