Representing Partial Programs with Blended Abstract Semantics

1 INTRODUCTION . Inductive program synthesis – the problem of inferring programs from examples – offers the promise of building machine learning systems that are interpretable , generalize quickly , and allow us automate software engineering tasks . In recent years , neurally-guided program synthesis , which uses deep learning to guide search over the space of possible programs , has emerged as a promising approach ( Balog et al. , 2016 ; Devlin et al. , 2017 ) . In this framework , partially-constructed programs are judged to determine if they are on the right track and to predict where to search next . A key challenge in neural program synthesis is representing the behavior of partially written programs , in order to make these judgments . In this work , we present a novel method for representing the semantic content of partially written code , which can be used to guide search to solve program synthesis tasks . Consider a tower construction domain in which a hand drops blocks , Tetris-style , onto a vertical 2D scene ( Figure 1 ) . In this domain , a function buildColumn ( n ) stacks n vertically-oriented blocks at the current cursor location , and moveHand ( n ) moves the cursor n spaces to the right . Given an imageX of a scene , our task is to write a program which builds a tower matching the imageX . To do this , a model can perform search in the space of programs , iteratively adding code until the program is complete . While attempting to synthesize a program , imagine arriving at a partially-constructed program s ( short for sketch ) , where HOLE signifies unfinished code : s = loop ( 4 , [ buildColumn ( 1 ) , moveHand ( < HOLE > ) ] ) Note that this partial program can not reach the goal state , because the target image has columns of height 2 , but this program can only build columns of height 1 . For an algorithm to determine if it should expand s or explore another part of the search space , it needs to determine whether s is ∗Correspondence to mnye @ mit.edu . CONTEXT f EMBED EMBED 4 3 EMBED1 EMBED + EMBED HOLE 1 x→3 CONTEXT HOLEx→3 + ( c ) on track to satisfy the goal . Answering this question requires an effective representation of partial programs . Existing neural program synthesis techniques differ in how they represent programs . Some represent programs by their syntax ( Devlin et al. , 2017 ; Allamanis et al. , 2018 ) , producing vector representations of program structure using sequence or graph neural networks . Recently , approaches which instead represent partial programs via their semantic state have been shown to be particularly effective . In these execution-guided neural synthesis approaches ( Chen et al. , 2018 ; Ellis et al. , 2019 ; Zohar & Wolf , 2018 ) , partial programs are executed and represented with their return values . ( To see why this is helpful , consider two distinct syntactic expressions 2+1 and 6/2 ; a syntax-based model might assign them different representations , whereas a model using a semantic representation will represent both as equivalent to 3 . ) However , execution is not always possible for a partial program . In our running example , before the HOLE is filled with an integer value , we can not meaningfully execute the partially-written loop in s. This is a common problem for languages containing higher-order functions and control flow , where execution of partially written code is often ill-defined.1 Thus , a key question is : How might we represent the semantics of unfinished code ? A classic method for representing program state , known as abstract interpretation ( Cousot & Cousot , 1977 ) , can be used to reason about the set of states that a partial program could reach , given the possible instantiations of the unfinished parts of the program . Using abstract interpretation , an approximate execution model can determine if an unfinished program will eventually satisfy a goal specification . For example , in the tower-building domain , an abstract interpreter could be designed to track , for every horizontal location , the minimum tower height that all continuations are guaranteed to exceeded . However , this technique is often low-precision : hand-designed abstract execution models greatly overapproximate the set of possible execution states , and do not automatically adapt themselves to the strengths or weaknesses of specific search algorithms . We hypothesize that , by mimicking the compositional structure of abstract interpretation , learned components can be used to effectively represent ambiguous program state . In this work , we make two contributions : we introduce neural abstract semantics , in which a compositional , approximate execution model is used to represent partially written code . This approach can be extended to blended abstract semantics , which aims to represent the state of unfinished programs as faithfully as possible by concretely executing program components whenever possible , and otherwise , approximating program state with a learned abstract execution model . 1See Peleg et al . ( 2020 ) for a discussion in the context of bottom-up synthesis . Consider again the partial program s and the blended abstract semantics encoding in Figure 1 . The sub-expression buildColumn ( 1 ) is fully concrete , and can thus be concretely executed to render an image . On the other hand , for functions whose arguments are not fully defined , such as moveHand , we instead employ abstract neural modules to represent the execution state . For this example , blended neural execution makes it easy to recognize that s is not a suitable partial program , because no integer argument to moveHand—which controls the spacing between the columns— would make the state in s match the goal X . This combination of learned execution and concrete execution allows robust representation of partial programs , which can be used for downstream synthesis tasks . Our approach can effectively learn to represent partial program states for languages where previous execution-guided synthesis techniques are not applicable . In summary , • We introduce blended neural semantics , a novel method for representing the semantic state of partially written programs inspired by abstract interpretation . • We describe how to integrate our program representations into existing approaches for learning search policies and search heuristics . • We validate our new approach with program synthesis experiments in three domains : tower construction , list processing , and string editing . We show that our approach outperforms neural synthesis baselines , solving at least 5 % more programs in each domain . 2 RELATED WORK . Synthesizing programs from examples is a classic AI problem ( Backus et al. , 1957 ) which has seen advances from the Programming Languages community ( Gulwani et al. , 2017 ; Gottschlich et al. , 2018 ; Solar-Lezama , 2008 ) . Neurally-guided search Recently , much progress has been made using neural methods to aid search . Enumerative approaches ( Balog et al. , 2016 ; Shi et al. , 2020 ) use neural methods to guide an enumerative synthesizer , and can be quite suitable for small-scale domains , but can scale poorly to larger programs and domains . Translation-based techniques ( Devlin et al. , 2017 ) treat program synthesis as a sequence-to-sequence problem , and employ state-of-the-art neural sequence modeling techniques , such as recurrent neural networks ( RNNs ) with attention . Hybrid approaches which use sketches ( Murali et al. , 2017 ; Nye et al. , 2019 ; Dong & Lapata , 2018 ) trade off computation between translation and enumeration components . These techniques can exhibit better generalization than translation-based approaches but more precise predictions than enumerative approaches ( Nye et al. , 2019 ) . To combine neural learning and search , our approach follows the framework laid out in Ellis et al . ( 2019 ) , where neural networks are used to guide a search over the space of possible partial programs defining a Markov decision process ( MDP ) . Program representation Prior work has studied neural representation of programs . Odena & Sutton ( 2019 ) propose property signatures to represent input-output examples , and use property signatures to guide an enumerative search . Graph neural networks have also been used to encode the syntax of programs ( Allamanis et al. , 2018 ; Brockschmidt et al. , 2018 ; Dinella et al. , 2019 ) for bug fixing , variable naming , and synthesis . This work has mostly focused on performing small edits to programs from real datasets . Our objective is to synthesize entire programs from specifications . Execution-guided synthesis Recent work has introduced the notion of “ execution-guided neural program synthesis ” ( Ellis et al. , 2019 ; Chen et al. , 2018 ; Zohar & Wolf , 2018 ) . In this framework , the neural representations used for search are conditioned on the executed program state instead of the program syntax . These techniques have been shown to solve difficult search problems outside the scope of enumerate or syntax-based neural synthesis alone . However , such execution-guided approaches have several limitations . We aim to generalize execution guided synthesis , so that it can be applicable to a wider range of domains , search techniques , and programming language constructs . Abstract Interpretation Our work is directly inspired by abstract interpretation-based synthesis ( Singh & Solar-Lezama , 2011 ; Wang et al. , 2017 ; Hu et al. , 2020 ) . These approaches use abstract interpretation ( Cousot & Cousot , 1977 ) to determine if a candidate partial program is realizable under the given specification , thereby pruning the search space of programs . We see our approach as a learning-based extension to this line of work . Neural Modules We employ neural module networks ( Andreas et al. , 2016 ; Johnson et al. , 2017 ) to implement blended abstract semantics , which aims to provide a learned execution scheme inspired by abstract interpretation . This approach is also related to other tree-structured encoders ( Socher et al. , 2011 ; Dyer et al. , 2016 ) . 3 BLENDED ABSTRACT SEMANTICS . Consider the problem of synthesizing arithmetic expressions from input–output pairs . Suppose we have the following context-free grammar for expressions : G = E→ E * E | E + E | x | 1 | 2 | 3 | 4 and a specification X consisting of the input–output pairs { ( x = 3 , y = 7 ) , ( x = 5 , y = 11 ) } . Suppose further that we have a candidate program ( 2 * x ) + 1 ∈ G. To check that this program is consistent with the specification , we can evaluate it on the inputs x in the specification according to the concrete semantics of the language : to evaluate ( 2 * x ) + 1 on the example ( x = 3 , y = 7 ) , we observe that the expression ( 2 * x ) evaluates to the integer 6 , and the expression 1 evaluates to the integer 1 ; thus the whole expression evaluates to 7 , as desired . Repeating this process with x = 5 returns the value 11 . Formally : Let C denote a context ( e.g . { x = 3 } ) ) . The concrete value of an expression E in a context C is:2 JEKC = JkKC = k a constant k JxKC|=x=v = v a variable x is evaluated to its value in the context Jf ( E1 · · · ) KC = run [ f , C ] ( JE1KC · · · ) recursively evaluate the arguments , then run f The goal of synthesis is to find an expression E : JEKx = y under concrete semantics . Iterative construction of partial programs Where did the expression ( 2 * x ) + 1 come from ? Neurally-guided synthesis techniques generally employ discrete search procedures . In this work , we use top-down search : starting with the top-level ( incomplete ) expression HOLE , we consider all possible expansions , ( HOLE→ HOLE + HOLE , HOLE→ 1 , HOLE→ 2 , . . . ) and select the one we believe is most likely to succeed ( Figure 1 left ) . Concrete semantics can not be used for this selection , because expressions such as x + HOLE are incomplete and can not be executed . Thus , we need a different mechanism to guide search . The more effectively we can filter the set of incomplete candidate programs , the faster our synthesis algorithm will be . Conventional abstract interpretation solves this problem by defining an alternative semantics for which even incomplete expressions can be evaluated . Consider the candidate expression HOLE * 2 . No matter how the HOLE is filled , the expression returns an even number , so it can not be consistent with the specification above . In many problems , we can define a space of “ abstract values ” ( like even integer ) and abstract semantics so that the abstract value of a partial program can be determined . This allows us to rule out partial programs on the basis of the abstraction alone ( Wang et al. , 2017 ) . However , constructing appropriate abstractions is difficult and requires domainspecific engineering ; an ideal procedure would automatically discover an effective space of abstract interpretations . Neural abstract semantics [ [ · ] ] nn As a first step , we implement the abstract interpretation procedure with a neural network . This is a natural choice : neural networks excel at representation learning , and the goal of abstract interpretation is to encode an informative representation of the set of values that could be returned by a partial program . For the program 1 + HOLE , we can encode the expression 1 to a learned representation ( Figure 2a , top ) , likewise encode HOLE ( Figure 2c ) , and finally employ a learned abstract implementation of the + operation ( Figure 2b ) . For concrete leaf nodes , such as constants or variables bound to constants , neural semantics are given using a state embedding function EMBED ( · ) , which maps any concrete state in the programming language into a vector representation : EMBED : ( State | Rd ) → Rd . If the input to EMBED is already vector-valued , EMBED performs the identity operation . Neural placeholders provide 2Domains with lambdas have slightly more complicated semantics . See Appendix A for details . Published as a conference paper at ICLR 2021 Neural abstract semantics loop ( 4 , seq ( buildColumn ( HOLE ) , HOLE ) ) loop ( 4 , seq ( buildColumn ( 1 ) , moveHand ( HOLE ) ) ) loop ( 4 , seq ( buildColumn ( 1 ) , HOLE ) ) ... ... H E H E H E SEARCH SPACE GOAL loop 4 seq buildColumn1 moveHandHOLE loop 4 seq moveHandHOLE Blended abstract semantics loop 4 seq buildColumn 1 HOLEmoveHand RNN representation Value V ( s , X ) Policy π ( a ; s , X ) search state representation EMBED s EMBED EMBED EMBED EMBED a method for computing a vector representation of unwritten code , denoted by the HOLE token . To compute the representation for HOLE , we define a neural embedding function h which takes a context C and outputs a vector . For each built-in function f ( including higher-order functions ) , the neural abstract semantics of f are given by a separate neural module ( a learned vector-valued function as in Andreas et al . ( 2016 ) ) [ [ f ] ] nn with the same arity as f . Therefore , computing the neural semantics means applying the neural function [ [ f ] ] nn to its arguments , which returns a vector . Since the neural semantics mirrors the concrete semantics , its implementation does not require changes to the underlying programming language . Formally , neural semantics involve a slightly larger set of cases than concrete semantics : [ [ E ] ] nnC = [ [ k ] ] nnC = EMBED ( k ) a constant k is embedded [ [ x ] ] nnC|=x=v = EMBED ( v ) embed the value v of the variable x [ [ HOLE ] ] nnC = h ( C ) a neural placeholder based on context [ [ f ( E1 · · · ) ] ] nnC = [ [ f ] ] nn ( [ [ E1 ] ] nnC · · · ) using neural module [ [ f ] ] nn This encoding is only one way to define a neural semantics , adopting a relatively simple and generic representation for all program components . For a discussion of its limitations and other , more sophisticated representations that could be explored in future work , see Appendix C. Blended abstract semantics [ [ · ] ] blend Notice that for an expression such as ( 2 * x ) + HOLE , the concrete value of the sub-expression ( 2 * x ) is known , since it contains no holes . The neural semantics above don ’ t make use of this knowledge . To improve upon this , we extend neural semantics and introduce blended semantics , which alternates between neural and concrete interpretation as appropriate for a given expression : • If the expression is a constant or a variable , use the concrete semantics . • If the expression is a HOLE , use the neural semantics . • If the expression is a function call , recursively evaluate the expressions that are the arguments to the function . If all arguments evaluate to concrete values , execute the function concretely . If any argument evaluates to a vector representation , transform all concrete values to vectors using EMBED and apply the neural semantics of the function . Formally , we can write : [ [ E ] ] blendC = [ [ k ] ] blendC = JkKC = k a constant k [ [ x ] ] blendC|=x=v = JxKC|=x=v = v variable x in context [ [ HOLE ] ] blendC = [ [ HOLE ] ] nn C = h ( C ) a neural placeholder based on context [ [ f ( E1 · · · ) ] ] blendC = JfK ( [ [ E1 ] ] blendC · · · ) if all arguments are concrete [ [ f ( E1 · · · ) ] ] blendC = [ [ f ] ] nn ( EMBED ( [ [ E1 ] ] blendC ) · · · ) if any arguments are vectors Because blended abstract semantics replaces concrete sub-components with their concrete values , we expect blended semantics to result in more robust representations , especially for long or complex programs where large portions can be concretely executed .

Summary: This paper proposes an embedding mechanism for partial programs for search space exploration in example-driven synthesis. It executes a sub-expression concretely whenever possible and applies neural module networks on vector representations otherwise. The embeddings of partial programs and goal states are used for determining the next step towards expanding an unfilled hole. This method is evaluated on three benchmark sets: tower construction, functional list processing and string editing.