{'fraction_non_alphanumeric': 0.03334955106373568, 'fraction_numerical': 0.014043080189305144, 'mean_word_length': 4.48175536428658, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 0, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
Learning Fitness Functions for Genetic Algorithms

A genetic algorithm (GA) attempts to solve a problem using a pool of potential solutions that are iteratively refined using various selection techniques. Although GAs have been used successfully for many problems, one criticism is that hand-crafting a GA's fitness function, the test that aims to effectively guide its evolution, can be notably challenging. Moreover, the complexity of a GA's fitness function tends to grow proportionally with the complexity of the problem being solved. In this work, we present a novel approach to learn a GA's fitness function. For the purpose of simplicity, we limit the demonstration of this technique to automatic software program generation. However, our system has no specific restrictions that prevent it from being applied to other domains. We also augment the GA evolutionary process with a minimally intrusive search heuristic. This heuristic improves the GA's ability to discover correct programs from ones that are approximately correct and does so with negligible computational overhead. We compare our approach to two state-of-the-art program generation systems and demonstrate that it finds more correct programs with fewer candidate program generations.


INTRODUCTION
In recent years, there has been notable progress in the space of automatic software generation, also known as machine programming (MP) (Gottschlich et al., 2018;Ratner et al., 2019). MP can be achieved in many ways. One way is by using formal program synthesis, a technique that uses formal methods and rules to generate programs (Manna & Waldinger, 1975). Formal program synthesis usually guarantees some program properties by evaluating a generated program's semantics against a corresponding specification (Gulwani et al., 2012;Alur et al., 2015). Although useful, a program generated by such formal synthesis techniques can often be limited by exponentially increasing computational overhead that grows proportionally with the program's instruction size (Heule et al., 2016;Bodík & Jobstmann, 2013;Solar-Lezama et al., 2006;Loncaric et al., 2018;Cheung et al., 2012).
An alternative to a formal methods approach for MP is to use machine learning (ML) (Balog et al., 2017;Raychev et al., 2014;Bunel et al., 2018;Reed & de Freitas, 2016; Cai et al., 2017;Becker & Gottschlich, 2017;Real et al., 2017;. ML for machine programming differs from traditional formal program synthesis in that it generally does not provide correctness guarantees. Instead, ML-driven MP systems are usually only probabilistically correct (i.e., their results are derived from sample data relying on statistical significance) (Murphy, 2012). Such ML approaches tend to explore software program generation using an objective function (Goodfellow et al., 2016). Objective functions are used to guide an ML system's exploration of a problem space. For example, backpropagation, the objective function used in deep neural networks (DNNs), is a gradient-based optimization algorithm that aims to iteratively reduce the error of the DNN using mathematical differentiation (Rumelhart et al., 1986).
Objective functions can also come in the form of heuristics, which are commonly used in genetic algorithms (GAs). A genetic algorithm is a machine learning technique that attempts to solve a problem from a pool of candidate solutions. These generated candidates are iteratively (i.e., evolutionarily) refined and mutated after qualifying from various grading criteria. The primary grading system used in genetic algorithms is the fitness function. Fitness functions are usually hand-crafted heuristics that grade the approximate correctness of candidate solutions.
While GAs have had demonstrable success in their application in both research and industrial communities (Korns, 2011;Such et al., 2017;Real et al., 2018), an open challenge is in creating simple, yet effective fitness functions.

arXiv:1908.08783v2 [cs.SE] 10 Sep 2019
Contrary to this goal, fitness function complexity tends to increase proportionally with the problem being solved. In this paper, we explore an approach to automatically generate them, making the following technical contributions: • Fitness Function: Our fundamental contribution is in the automation of fitness functions for genetic algorithms. To the best of our knowledge, our work is the first of its kind to use a neural network as a GA's fitness function for software generation.
• Convergence: A secondary contribution is in our utilization of local neighborhood search to improve the convergence of approximately correct candidate solutions. We propose two such approaches and demonstrate their efficacy in a number of benchmarks.
• Generality: We demonstrate that our approach can support different neural network fitness functions, uniformly. While our experiments are strictly in the space of MP, we are not aware of any restrictions from utilizing our fitness function automation technique in other domains.
• Metric: We contribute with a new metric suitable for MP domain. While prior work (Balog et al., 2017;Zohar & Wolf, 2018b) aims at optimizing program generation time, we argue that program generation time does not fully capture efficiency of the generation algorithm. Instead it captures implementation efficiency of the algorithm. So, we propose to use "search space" size (i.e., how many candidate programs have been searched) as an alternative metric.
In Section 2, we briefly describe related work. In Section 3, we describe the general problem statement and the way we constrain it. In Section 4, we discuss the NetSyn framework. In Section 5, we describe our experimental results and in Section 6 we conclude.

BACKGROUND
The goal of automatically generating software dates back to at least the 1950s (Backus et al., 1957). However, there have been several technical challenges that have restricted a deeper exploration of MP when using only formally verified program synthesis techniques (e.g., proper program construction, effective pruning of the computational search space, data size and type limitations, etc.) (Gulwani, 2011;Solar-Lezama, 2008;Kamil et al., 2016).
To address this, there has been a surge of research exploring machine programming using neural networks (NNs) (Balog et al., 2017;Raychev et al., 2014;Bunel et al., 2018;Reed & de Freitas, 2016;Cai et al., 2017;Real et al., 2017;. For example, DeepCoder (Balog et al., 2017) trains a DNN with input-output examples to predict the probabilities of the functions that are most likely to be used in a program. Raychev et al. take a different approach and use an n-gram model (a technique that analyzes a contiguous sequence of elements) to predict the functions that are most likely to complete a partially constructed program (Raychev et al., 2014). Bunel et al. explore a unique approach that combines reinforcement learning (RL) with a supervised model to find semantically correct programs (Bunel et al., 2018). These are only a few of the research efforts in MP space using neural nets (Reed & de Freitas, 2016;Cai et al., 2017).
Unfortunately, even with this notable progress, GAs can be challenging to use due to the complexity of hand-crafting a GA's fitness function (FF). In this paper, we attempt to address this issue by automating the generation of the FF by representing its structure as a neural network, which we refer to as a neural network fitness function (NN-FF).
We are not the first to propose such an approach. There are at least two prior works that have explored the automation of FFs using neural networks. Matos Dias et al. automated them for IMRT beam angle optimization, while Khuntia et al. used them for rectangular microstrip antenna design automation (Matos Dias et al., 2014;Khuntia et al., 2005). At the highest level, these systems' automated NN-FFs behave as an approximation of a known mathematical model. In essence, they act as a mathematical approximation proxy.
NetSyn's NN-FFs, however, behaves like a prediction proxy, which attempts to predict the likelihood that a given, incorrect solution will eventually converge to become a correct one. This is because in the MP domain, we do not know the order of operations that would create the correct target program. As such, NetSyn's NN-FFs predict the likelihood that a generated program will eventually converge on a correct one, whose generated output matches the given output. In essence, this provides us with what we consider to be the first of its kind automated prediction FF for big data learning.

PROBLEM STATEMENT
The goal of NetSyn is to automatically generate a correct software program, P , provided a given input (I) and output (O). We define correct to mean that, provided a given input, I, the output generated by P exactly matches the given output, O. To more precisely formalize the problem definition, we introduce the following notation.

Mathematical Notation
be a set of m input-output pairs, such that the inputs come from program P a and the outputs come from program P b . Then, S to ti is a set of input-output pairs provided by the user defining the desired behavior of a target program P t to be synthesized. P t is written in the domain specific language (DSL) as discussed in Section 3.2. The goal of this work is to find P t such that P t ≡ P t . In other words, NetSyn should generate a program P t such that ∀j ∈ {x} m x=1 : To assist the synthesis process, there will be a set E of training examples, with each example being a program P e written in the DSL. Throughout the paper, we use the subscripts/superscripts e, g, and t to refer to (e)xample, (g)enerated, and (t)arget programs, respectively.

NetSyn's Domain Specific Language (DSL)
To constrain the problem space, as others have done before us (Balog et al., 2017), we restrict the operations used by NetSyn to a DSL we constructed specifically for it.
NetSyn's DSL is similar to that of DeepCoder and is inspired by SQL and LINQ (Dinesh et al., 2007). The only data types in NetSyn's DSL are (i) integers and (ii) lists of integers. A program using this DSL is a sequence of high level functions, each taking one or two arguments and returning one output. Similar to, but not precisely like, Halide's language design, there is no explicit control flow (conditionals or looping) in our DSL (Mullapudi et al., 2016;Adams et al., 2019).
Arguments to functions are not specified via named variables. Instead, each function uses the output of the previously executed function, which produces the type of output that is used as input to the next function. The first function of each program uses the provided input, I. If I contains a type mismatch, default values are used (i.e., 0 for integers and empty lists for a list of integers). The final output of all generated programs is the output of the last function.
When taken as a whole, NetSyn's DSL has a novelty and amenability to genetic algorithms. In short, NetSyn's DSL is defined such that all possible programs are valid by construction. This is particularly important in the GA evolutionary process such that when genetic crossover occurs between two programs or mutation occurs within a single program, the resulting program will always be valid. This eliminates the need for GA pruning to identify valid programs.
NetSyn's DSL contains a total of 41 functions with varying degrees of complexity. Many of the operations emphasize list manipulation. Some higher-order functions also require lambda functions. See Appendix A for a full description.

NETSYN'S SYSTEM DESIGN
In this section, we describe NetSyn's design as illustrated in Figure 1. We begin with a brief overview of the three main phases of NetSyn and subsequently discuss some of the novel elements of these phases thereafter.

NetSyn's Phases
Data Preparation (Phase 0). To use NetSyn, one must have a dataset of (i) example programs (P e ), and (ii) inputoutput examples (S eo ei ) generated using those example programs. To generate these data, we synthetically created thousands of unique programs and corresponding input datasets for those programs. We then executed the programs using the synthesized input data, which produced the necessary output datasets.
Fitness Function Generation (Phase 1). Next, NetSyn uses the input-output examples from Phase 0 (S eo ei ) to train a neural network, which acts as a mapping of program input to program output. The resulting NN model is later used in the GA evolutionary process to automatically construct its fitness function. NetSyn uses this single NN model as a fitness function to synthesize multiple target programs. More details about this process are provided in Section 4.5.
Program Generation (Phase 2). Once the FF is modeled, NetSyn can begin program synthesis. It does this by creating a population of pseudo-random genes (i.e., candidate programs) of a given length and uses the neural networkbased FF to estimate the fitness of each gene. Higher graded genes are preferentially selected for crossover and mutation to produce the next generation of genes.
In general, NetSyn uses this process to evolve the genes from one generation to the next until it discovers a correct candidate program as verified by the input-output examples. From time to time, NetSyn takes the top N scoring genes from the population, determines the neighborhood of those genes, and looks for the target program using a local proximity search. If a correctly generated program is not found using this approach, NetSyn resumes with its evolutionary process, as described in Figure 1.
The following subsections provide a more detailed description of each of these processes. A more in-depth detail of the classical genetic algorithm elements (such as population size and mutation frequency) can be found in Appendix B.

Gene Encoding
NetSyn uses a value encoding approach where a gene ζ is represented as a sequence of values [C : C ∈ {x} |ΣDSL| x=1 ]. Σ DSL is the set of functions from NetSyn's DSL. C can be thought of as an identifier corresponding to one of the DSL functions. This encoding simplifies crossover and mutation implementation by eliminating the potential of invalid gene construction.

The Genetic Algorithm Process
To begin the GA process, NetSyn initializes the population with pseudo-randomly generated genes. Unless a correct program is found (i.e., an exact match of candidate program output compared to target output), the remaining genes are graded using the FF neural network model described in Phase 1. A small percentage (e.g., 20%) of top graded genes are moved into the next evolutionary phase in an unmodified fashion. This guarantees some of the top graded genes are identically preserved, aiding in forward progress guarantees.
The remaining genes are created through crossover or mutation with some probability. For crossover, two genes are selected using the Roulette Wheel algorithm with the crossover point selected pseudo-randomly (Goldberg, 1989). For mutation, one gene is Roulette Wheel selected and the mutation point in that gene is selected pseudo-randomly. The selected value C is mutated to some other pseudorandom value C such that C ∈ {x} |ΣDSL| x=1 and C = C. Crossover and mutation can sometimes lead to a new gene with dead code. NetSyn checks for dead code (Section 4.4). If dead code is present, NetSyn repeats crossover and mutation until a gene without dead code is produced.

Dead Code Elimination
Dead code elimination (DCE) is a classic compiler technique to remove code from a program that has no effect on the program's output (Debray et al., 2000). Dead code is possible in our list DSL if the output of a statement is never used. We implemented DCE in NetSyn by tracking the input/output dependencies between statements and eliminating those statements whose outputs are never used. NetSyn uses DCE during candidate program generation and during crossover/mutation to ensure that the effective length of the program is not less than the target program length due to the presence of dead code.

Neural Network-Based Fitness Function
As described earlier, NetSyn uses a NN to model its fitness function, referred to as NN-FF. To train the NN-FF, NetSyn uses a set of pseudo-random generated example programs, E, along with a set of pseudo-random inputs I. It then executes each program P e in E with its corresponding input I e in I to calculate the output set, O. For each P e in E, NetSyn takes a pseudo-randomly generated program P r , applies the previously generated input, I e (corresponding to P e ), to P r to produce output (O r ). It then compares the output of P r with P e to calculate fitness metrics.
To determine the fitness of a gene ζ g = [C g ] generated during the genetic algorithm, NetSyn executes the gene with inputs I t , producing an input-output set S go ti . The fitness function estimates the fitness of ζ g by using a combination of the generated output, S go ti , and the target program output, S to ti . A higher fitness score implies a gene that is closer to the target program than the other.
NetSyn trains its NN-FF to learn fitness metrics. The inputs for the neural network can be chosen from several options: (i) S ro ei only, which we call the IO model, (ii) S eo ei and S ro ei , which we call the IO 2 model and (iii) the difference between the inputs and outputs in S eo ei and S ro ei , which we call the IO δ model. In this way, the network is trained on a variety of program correctness levels, from entirely correct to entirely incorrect. During inference time, each generated candidate program P g behaves like P r and the target program P t behaves like P e . Therefore, IO model takes inputs from S go ti during inference. The case for IO 2 and IO δ models is similar. Details of how we trained the neural network can be found in Appendix B.
In contrast to NetSyn's NN-FF, we consider a commonly used FF based on edit distance, where the score of gene ζ g is the edit distance between [O t j ] n j=1 and [O g j ] n j=1 . We observed that an edit distance-based FF can lead to poor results for program synthesis, where target programs are found at roughly one-third the rate as NetSyn's NN-FF. As such, NetSyn uses its trained NN to predict the fitness of ζ g with respect to ζ t . In essence, NetSyn's FF is mapped to a big data problem where an NN learns to predict the fitness of a gene by training on programs from E.
We design the following three fitness metrics -common functions, longest common subsequence, and function probability -which we discuss next, and compare their performance in synthesizing programs in Section 5.
Common Functions NetSyn can use the number of common functions (CF) between ζ g and ζ t as a fitness metric for ζ g . In other words, the fitness score of ζ g is f CF ζg = |elems ζ g ∩ elems ζ t |. NetSyn constructs training data for f CF from E as described in Section 4.5 and feeds to a neural network for training. Because the output of the neural network will be an integer from 0 to len ζ t , the neural network can be designed as a multiclass classifier with a softmax layer as the final layer.
Longest Common Subsequence NetSyn can use longest common subsequence (LCS) between ζ g and ζ t as an alternative to CF. So, the fitness score of ζ g is f LCS ζg = len LCS (ζ g , ζ t ). Similar to CF, training data can be constructed from E which is then fed into a multiclass classifier neural network.
Function Probability DeepCoder proposed a probability map for the functions in DSL. We can construct a fitness metric using the probability map. Let us assume that the probability map is [p i : . A multiclass, multilabel neural network classifier with sigmoid activation functions used in the last layer can be used to predict the probability map. Training data can be constructed for the neural network using E. NetSyn can use the probability map to calculate the fitness score of ζ g as f FP ζg = Σ(p i : C i ∈ elems ζ g ). NetSyn can even use the probability map to guide the mutation process. For example, instead of mutating a function C with C that is selected randomly, NetSyn can select C using Roulette Wheel algorithm using the probability map.
Alternative Models NetSyn treats f CF and f LCS as multiclass classifiers. However, we did experiment with treating them as regression problems. We found that when treated as regression problems, the neural networks produced higher prediction error as the networks had a tendency to predict values close to the median of the values in the training set. Therefore, given the higher prediction errors of the fitness function, the GA performance of NetSyn degraded.
We also experimented with training a network to predict a correctness ordering among a set of genes. We note that the ultimate goal of the fitness score is to provide an order among genes for the Roulette Wheel algorithm. Rather than getting this ordering indirectly via a fitness score for each gene, we attempted to have the neural network predict this ordering directly. However, we were not able to train a network to predict this relative ordering whose accuracy was higher than the one for absolute fitness scores. We believe that there are other potential implementations for this relative ordering and that it may be possible for it to be made to work in the future.
Additionally, we tried a two-tier fitness function. The first tier was a neural network to predict whether a gene has a fitness score of 0 or not. In the event the fitness score was predicted to be non-zero, we used a second neural network to predict the actual non-zero value. This idea came from the intuition that since many genes have a fitness score of 0 (at least for initial generations), we can do a better job predicting those if we use a separate predictor for that purpose. Unfortunately, mispredictions in the first tier caused enough good genes to be eliminated that NetSyn's synthesis rate was reduced.
Finally, we explored training a bigram model (i.e., predicting pairs of functions appearing one after the other). This approach is complicated by the fact that over 99% of the 41 × 41 (i.e., number of DSL functions squared) bigram matrix are zeros. We tried a two-tiered neural network and principle component analysis to reduce the dimensionality of this matrix (Li & Wang, 2014). Our results using this bigram model in NetSyn were similar to that of DeepCoder, with up to 90% reduction in synthesis rate for singleton programs.

Neighborhood Search
Neighborhood search (NS), precisely defined below, checks some candidate genes in the neighborhood of the N top scoring genes from the genetic algorithm. The intuition behind NS is that if the target gene ζ t is in that neighborhood, NetSyn may be able to find it without relying on the genetic algorithm, which would likely result in a faster time to correct program synthesis.
NS Invocation When NetSyn has completed l generations, µ l−w+1,l will denote the average fitness score of genes for the last w iterations (i.e., from l−w+1 to l iterations) and µ 1,l−w will denote the average fitness scores before the last w iterations (i.e., from 1 to l − w iterations). Here, w is the sliding window. NetSyn invokes NS if µ l−w+1,l ≤ µ 1,l−w . The rationale is that under these conditions, NetSyn has not produced improved genes for the last w iterations (i.e., saturating). Therefore, it should check if the neighborhood contains ζ t .
Neighborhood Definition Algorithm 1 shows how to define and search a neighborhood. The algorithm is inspired by the principle of breadth first search (BFS). For each top scoring gene ζ g , NetSyn considers one function at a time starting from the first function of the gene to the last one. For each selected function NetSyn replaces that function with all other functions from Σ DSL , and inserts the resultant genes into the neighborhood set N . If ζ t is found in N , NetSyn stops there by returning the solution. Otherwise, it continues the search and returns to the genetic algorithm. The complexity of the search is O(N × len ζ g × |Σ DSL |), which is significantly smaller than the exponential search space used by a traditional BFS algorithm. Similar to BFS, NetSyn can define and search the neighborhood using an approach similar to depth first search (DFS). It is similar to Algorithm 1 except i will keep track of depth here. After the loop in line 4 finishes, NetSyn needs to pick the best scoring gene from N to replace ζ g before going to the next level of depth. The algorithmic complexity will remain the same. Figure 2 shows examples of neighborhood using BFS-and DFS-based approach.

Known Target Program Length
Like DeepCoder and PCCoder (Zohar & Wolf, 2018a), Net-Syn assumes a priori knowledge of the target program length and maintains all genes at that target length. However, we experimented with generating the initial genes with gene lengths following a normal distribution and also allowing crossover and mutation to change gene length. We found that this increased the time to solution and reduced the synthesis rate. This effect was particularly pronounced if the target program length was two or more functions larger or smaller than the mean initial gene length. Possible future work is to explore using a NN to predict program length to remove the need for this a priori knowledge.

EXPERIMENTAL RESULTS
We implemented NetSyn in C++ with a TensorFlow backend (Abadi et al., 2015). We also developed an interpreter for NetSyn's DSL to evaluate the generated programs. We used 50,000 pseudo-randomly generated unique example programs of length 4 to train the neural networks. We used 100 input-output examples for each program to generate the training data. For every approach, the same programs are used for training. 1 NetSyn's training time ranges between 3 and 8 hours using an NVidia Tesla P100 (Nvi). For our NN-FF, we chose an NN topology using three hidden layers with a softmax activation function in the output layer. Its input layer performs normalization to properly predict f CF and f LCS . The hidden layers have 48, 24, and 12 neurons, respectively.
We made these decisions based on an experimental evaluation of the FF-NN's accuracy (not included here for brevity). It uses a softmax activation function in the output layer, because CF and LCS fitness scores are modeled as a classification problem (as opposed to a regression problem). The normalization layer was chosen due to its ability to reduce the impact of absolute values of inputs. The function probability map was chosen because of its proposal in DeepCoder; as such, we used the same NN configuration to predict f FP . We used fixed length inputs (padded if necessary) for the neural networks.
To test NetSyn, we pseudo-randomly generated a total of 100 programs for each program length from 4 to 10. For each program length, 50 of the generated programs produce a singleton integer as the output; the rest output a list of integers. We therefore refer to the first 50 programs as singleton programs and the rest as list programs. We collected 5 input-output examples for each testing program to populate S to ti . We did not consider testing programs of length 1 to 3 because the search space seemed too small to warrant a sophisticated synthesis technique. When synthesizing a program using NetSyn, we execute it K times and take the average results, to eliminate noise, where K = 50.
Our experimental results aim to (i) demonstrate NetSyn's synthesis ability and compare its performance against two state-of-the-art approaches, DeepCoder and PCCoder, and to (ii) characterize the effectiveness of different design choices used in NetSyn.

Demonstration of Synthesis Ability
We ran three variants of NetSyn -NetSyn CF , NetSyn LCS , and NetSyn FP . As the names suggest, they use f CF , f LCS , and f FP FFs, respectively. For each version of NetSyn, we show both unoptimized and optimized synthesis time. Unoptimized time includes the total wall clock time of Net-Syn with our hardware testbed environment. Optimized time represents a speculation of the potential lowerbound of synthesis time using futuristic deep learning accelerators (Shawahna et al., 2019) that may eliminate some portion of the overall NN inferencing time.
We ran the publicly available implementations of Deep-Coder and PCCoder from their respective GitHub repositories. For DeepCoder, we used the best performing implementation based on "Sort and Add" enumerative search algorithm (Balog et al., 2017). For all the approaches, we set the maximum search space size to 3,000,000 candidate programs. If an approach does not find the solution prior to reaching that threshold, we conclude the experiment and label it as "solution not found," indicated by "-" in our tables. The results are shown in Table 1 and 2. Table 1 shows the comparative results using synthesis time as the metric. Columns 10% to 100% show the duration of time (in seconds) it takes to synthesize the corresponding percentage of programs. In general, all approaches can synthesize up to 30% programs within few seconds for all program lengths we tested. As expected, synthesis time increases as an approach attempts to synthesize more than 30% programs. DeepCoder and PCCoder usually find solutions faster than any version of NetSyn. Moreover, the synthesis time tends to increase for larger length programs. However, when the search space is constrained to some maximum, NetSyn tends to synthesize more programs. Among the fitness functions, f CF and f LCS have comparable synthesis rate and time whereas f FP usually performs worse. NetSyn synthesizes programs at a rate as low as 50% (in case of NetSyn FP for 10 length programs) to as high as 98% (in case of NetSyn FP for 5 length programs). In summary, for any program length, NetSyn synthesizes more programs than either DeepCoder or PCCoder although it takes more time to do so. Table 2 shows the comparative results using our proposed new metric: search space. For each test program, we count the number of candidate programs searched before the experiment has concluded by either finding a correct program or exceeding the threshold. The number of candidate programs searched is expressed as a percentage of the maximum search space threshold (i.e., 3,000,000 candidate programs).
For all approaches, up to 30% of the programs can be synthesized by searching less than 2% of the maximum search space. Search space use increases when an approach tries to synthesize more programs. In general, DeepCoder and PCCoder search more candidate programs than NetSyn. For example, for synthesizing programs of length 5, DeepCoder and PCCoder use 37% and 33% search space to synthesize 40% and 50% programs, respectively. In comparison, Net-Syn can synthesize upwards of 90% programs by using only 30% search space.
In other words, NetSyn is more efficient in generating and searching likely target programs. Even for length 10 programs, NetSyn can generate 70% of the programs using only 24% of the maximum search space. In contrast, DeepCoder and PCCoder cannot synthesize more than 50% and 60% of the programs even if they use the maximum search space. In summary, NetSyns synthesis technique is more efficient than both DeepCoder and PCCoder in how it generates and searches candidate programs to find a solution.

Characterization of NetSyn
In this section, we characterize the effect of different fitness functions, neighborhood search algorithms, and DSL function types on synthesis process. To explain the details of different choices, we show the results in this section based on programs of length 4. However, our general observations hold for longer length programs.
To synthesize a particular program, we ran NetSyn K times, where K = 50, to generate a statistically significant result. Thus, for a total of T testing programs of a particular length, where T = 100, we ran a total of K × T (5,000) experiments. Figure 3(a) shows the percentage of those experiments (separated by singleton and list types) in which the target program was synthesized. NetSyn synthesized at the highest rate when CF-based fitness function is used (85%), whether NS is used or not. Moreover, BFS-based NS tends to produce more correct programs. In comparison, FP-based fitness functions caused NetSyn to synthesize programs at a lower rate (46%), performing roughly an order <1s <1s <1s 164s 957s 1121s 1196s ---NetSyn CF − Opt 66% <1s <1s <1s 85s 674s 826s 890s ---  of magnitude worse for singleton programs. This is caused by the difficulty in predicting probabilities of all functions when the output is a single integer (and therefore, contains less information compared to a list type output). For list programs, the synthesis rate of each approach is comparable. For longer length programs, the synthesis rate decreases, but the synthesis ratio between singleton and list programs is similar. Figure 3(b) shows the effect of using IO, IO 2 , and IO δ models for inputs of the neural network. The FP-based fitness function only works with IO model and hence, is not shown here. In general, IO model is the most effective. This is counter-intuitive because the other models contain more information. However, our analysis found that although the other models had lower synthesis rates, they expedited the synthesis time. In other words, the other models tend to specialize for particular types of programs.      Table 3 shows how many unique programs (where length = 4) that the different approaches were able to synthesize. Both CF-and LCS-based fitness functions enabled NetSyn to synthesize 99 of 100 unique programs. The one program that NetSyn was not able to synthesize (#37) contains DELETE and ACCESS functions. DELETE deletes all occurrences of int X in list L whereas ACCESS returns the N -th element of a list. Both functions are difficult to predict because the input and output of these two functions behave differently depending on both arguments. Program #11 also contains these functions, which the CF-based approach was able to synthesize 15 out of 50 times (the second lowest synthesis rate after #37). The FP-based fitness function was able to synthesize 63 of 100 unique programs. All three approaches correctly synthesized every list program. This implies, counterintuitively, that singleton programs are harder to synthesize. Figure 4 shows the synthesis rate of different programs and functions. Program 1 to 50 are singleton programs and have lower synthesis rate in all three fitness function choices. Particularly, the FP-based approach has a low synthesis rate for singleton programs. Functions 1 to 12 produce singleton integer and tend to cause lower synthesis rate for any program that contains them. To shed more light in this issue, Figure 5 shows synthesis rate across different functions. The synthesis rate for a function is at least 40% for the CF-based approach, whereas for the FPbased approach, four functions cannot be synthesized at all. Functions corresponding to each number are shown in In this appendix, we provide more details about the list DSL that NetSyn uses to generate programs. Our list DSL has only two implicit data types, integer and list of integer. A program in this DSL is a sequence of statements, each of which is a call to one of the 41 functions defined in the DSL. There are no explicit variables, nor conditionals, nor explicit control flow operations in the DSL, although many of the functions in the DSL are high-level and contain implicit conditionals and control flow within them. Each of the 41 functions in the DSL takes one or two arguments, each being of integer or list of integer type, and returns exactly one output, also of integer or list of integer type. Given these rules, there are 10 possible function signatures. However, only 5 of these signatures occur for the functions we chose to be part of the DSL.
The following sections are broken down by the function signature, wherein all the functions in the DSL having that signature are described.
Instead of named variables, each time a function call requires an argument of a particular type, our DSL's runtime searches backwards and finds the most recently executed function that returns an output of the required type and then uses that output as the current function's input. Thus, for the first statement in the program, there will be no previous function's output from which to draw the arguments for the first function. When there is no previous output of the correct type, then our DSL's runtime looks at the arguments to the program itself to provide those values. Moreover, it is possible for the program's inputs to not provide a value of the requested type. In such cases, the runtime provides a default value for missing inputs, 0 in the case of integer and an empty list in the case of list of integer. For example, let us say that a program is given a list of integer as input and that the first three functions called in the program each consume and produce a list of integer. Now, let us assume that the fourth function called takes an integer and a list of integer as input. The list of integer input will use the list of integer output from the previous function call. The DSL runtime will search backwards and find that none of the previous function calls produced integer output and that no integer input is present in the program's inputs either. Thus, the runtime would provide the value 0 as the integer input to this fourth function call. The final output of a program is the output of the last function called.
Thus, our language is defined in such a way that so long as the program consists only of calls to one of the 41 functions provided by the DSL, that these programs are valid by construction. Each of the 41 functions is guaranteed to finish in a finite time and there are no looping constructs in the DSL, and thus, programs in our DSL are guaranteed to finish. This property allows our system to not have to monitor the programs that they execute to detect potentially infinite loops. Moreover, so long as the implementations of those 41 functions are secure and have no potential for memory corruption then programs in our DSL are similarly guaranteed to be secure and not crash and thus we do not require any sandboxing techniques. When our system performs crossover between two candidate programs, any arbitrary cut points in both of the parent programs will result in a child program that is also valid by construction. Thus, our system need not test that programs created via crossover or mutation are valid.
In the following sections, [] is used to indicate the type list of integer whereas int is used to indicate the integer type. The type after the arrow is used to indicate the output type of the function.

A.1 Functions with the signature [] → int
There are 9 functions in our DSL that take a list of integer as input and return an integer as output.

A.1.1 HEAD (Function 6)
This function returns the first item in the input list. If the list is empty, a 0 is returned.

A.1.2 LAST (Function 7)
This function returns the last item in the input list. If the list is empty, a 0 is returned.

A.1.3 MINIMUM (Function 8)
This function returns the smallest integer in the input list. If the list is empty, a 0 is returned.

A.1.4 MAXIMUM (Function 9)
This function returns the largest integer in the input list. If the list is empty, a 0 is returned.

A.1.5 SUM (Function 11)
This functions returns the sum of all the integers in the input list. If the list is empty, a 0 is returned.

A.1.6 COUNT (Function 2-5)
This function returns the number of items in the list that satisfy the criteria specified by the additional lambda. Each possible lambda is counted as a different function. Thus, there are 4 COUNT functions having lambdas: ¿0, ¡0, odd, even.

A.2 Functions with the signature [] → []
There are 21 functions in our DSL that take a list of integer as input and produce a list of integer as output.

A.2.1 REVERSE (Function 29)
This function returns a list containing all the elements of the input list but in reverse order.

A.2.2 SORT (Function 35)
This function returns a list containing all the elements of the input list in sorted order.

A.2.3 MAP (Function 19-28)
This function applies a lambda to each element of the input list and creates the output list from the outputs of those lambdas. Let In be the nth element of the input list to MAP and let On be the nth element of the output list from Map. MAP produces an output list such that On=lambda(In) for all n. There are 10 MAP functions corresponding to the following lambdas: +1,-1,*2,*3,*4,/2,/3,/4,*(-1),ˆ2.

A.2.4 FILTER (Function 14-17)
This function returns a list containing only those elements in the input list satisfying the criteria specified by the additional lambda.
Ordering is maintained in the output list relative to the input list for those elements satisfying the criteria. There are 4 FILTER functions having the lambdas: ¿0, ¡0, odd, even.

A.2.5 SCANL1 (Function 30-34)
Let In be the nth element of the input list to SCANL1 and let On be the nth element of the output list from SCANL1. This function produces an output list as follows: There are 5 SCANL1 functions corresponding to the following lambdas: +, -, *, min, max.

A.3 Functions with the signature int,[] → []
There are 4 functions in our DSL that take an integer and a list of integer as input and produce a list of integer as output.

A.3.1 TAKE (Function 36)
This function returns a list consisting of the first N items of the input list where N is the smaller of the integer argument to this function and the size of the input list.

A.3.2 DROP (Function 13)
This function returns a list in which the first N items of the input list are omitted, where N is the integer argument to this function.

A.3.3 DELETE (Function 12)
This function returns a list in which all the elements of the input list having value X are omitted where X is the integer argument to this function.

A.3.4 INSERT (Function 18)
This function returns a list where the value X is appended to the end of the input list, where X is the integer argument to this function.

A.4 Functions with the signature [],[] → []
There is only one function in our DSL that takes two lists of integers and returns another list of integers.

A.4.1 ZIPWITH (Function 37-41)
This function returns a list whose length is equal to the length of the smaller input list. Let On be the nth element of the output list from ZIPWITH. Moreover, let I 1 n and I 2 n be the nth elements of the first and second input lists respectively. This function creates the output list such that On=lambda(I 1 n , I 2 n ). There are 5 ZIPWITH functions corresponding to the following lambdas: +, -, *, min, max.

A.5 Functions with the signature int,[] → int
There are two functions in our DSL that take an integer and list of integer and return an integer.

A.5.1 ACCESS (Function 1)
This function returns the Nth element of the input list, where N is the integer argument to this function. If N is less than 0 or greater than the length of the input list then 0 is returned.

A.5.2 SEARCH (Function 10)
This function return the position in the input list where the value X is first found, where X is the integer argument to this function. If no such value is present in the list, then -1 is returned. B.2 How we generate training dataset for the neural network For our two approaches (f LCS and f F P ), we created 3 types of data sets for 3 different models (IO, IO 2 , IO δ ). We used 50,000 programs as base program, and to compare, we chose 150 different other programs. These two sets of programs are compared with each other to get the number of common function or longest common sub-sequence between them. In each comparison, we created 100 input-output examples that lead to total 750 million data points. For IO model we generated our dataset from the base program but for IO 2 and IO δ model we need another output that we created with the comparable program by passing the inputs. Each input or output were padded to fixed 12 dimension and were joined together. For the IO δ model we took absolute difference between input and corresponding two different outputs. Also add the information of dimension difference of two output. Thus for the three models input dimension were 24 (IO), 36 (IO 2 ), 25 (IO δ ).
With our training programs and given input-output examples we created our dataset. We split out the dataset into training and testing set in a ratio of 3:1. We also randomized the dataset before splitting. Data were normalized before feeding into the neural network.

B.3 Training of Neural Network
We used 3 hidden layers in our model. Our models predicted common functions/longest common subsequence between the target programs and generated programs from EA by using input-output examples. We predicted that value as a classification output.
For the DeepCoder model, we used 3 hidden layers with 256 neurons each. We passed the input through the embedding layer connected to the input neurons. We took the average for the inputoutput examples and predicted function probability.