Matthew Bowers, Theo X. Olausson, Lionel Wong, Gabriel Grand, Joshua B. Tenenbaum, Kevin Ellis, Armando Solar-Lezama
6 min
How can we efficiently learn functional abstractions from a corpus of programs to improve code conciseness and synthesis performance? Existing deductive library learning approaches, such as DreamCoder, often struggle with memory and computational scaling as the size and complexity of the program corpus increase.
The authors introduce Corpus-Guided Top-Down Synthesis (CTS), a novel branch-and-bound algorithm implemented in a tool called Stitch. Unlike deductive methods that rely on expensive, semantics-preserving rewrite rules to refactor code, Stitch directly synthesizes abstractions by searching the space of possible function bodies. It uses a guiding utility function—based on program compression—to prioritize promising search branches and employs aggressive pruning techniques, including upper-bound pruning and strict dominance pruning, to discard suboptimal paths early. The algorithm is also designed as an anytime procedure, allowing it to provide high-quality results even when terminated before completion.
Stitch demonstrates dramatic performance gains compared to the state-of-the-art DreamCoder algorithm. Across standard benchmarks, Stitch learns libraries of equal or better quality while being 3-4 orders of magnitude faster and using 2 orders of magnitude less memory. Furthermore, Stitch successfully scales to large, complex datasets (such as graphics and planning programs) that are computationally intractable for prior deductive approaches. The authors also show that Stitch is robust to early stopping and can be combined with deductive rewrite systems to recover higher-order functions while retaining its efficiency.
This work provides a highly scalable solution to the library learning problem, which is a critical component of modern program synthesis. By enabling the discovery of reusable abstractions in large-scale codebases, Stitch helps bridge the gap between low-level primitives and high-level, human-readable code. Its anytime nature and efficiency make it a practical tool for real-world synthesis tasks where computational resources are limited.
This paper introduces corpus-guided top-down synthesis as a mechanism for synthesizing library functions that capture common functionality from a corpus of programs in a domain specific language (DSL). The algorithm builds abstractions directly from initial DSL primitives, using syntactic pattern matching of intermediate abstractions to intelligently prune the search space and guide the algorithm towards abstractions that maximally capture shared structures in the corpus. We present an implementation of the approach in a tool called Stitch and evaluate it against the state-of-the-art deductive library learning algorithm from DreamCoder. Our evaluation shows that Stitch is 3-4 orders of magnitude faster and uses 2 orders of magnitude less memory while maintaining comparable or better library quality (as measured by compressivity). We also demonstrate Stitch’s scalability on corpora containing hundreds of complex programs that are intractable with prior deductive approaches and show empirically that it is robust to terminating the search procedure early—further allowing it to scale to challenging datasets by means of early stopping.
Alex: [concluding] Precisely. The utility function is the lever that defines what a good abstraction is. By framing it as a compression objective, the authors have created a tool that scales to hundreds of complex programs that were previously intractable.
Alex: [analytical, even pace] The most effective way to learn functional abstractions from a program corpus is to treat library learning as a top-down synthesis problem, rather than a deductive refactoring task. This approach, known as corpus-guided top-down synthesis, comes from the work of Matthew Bowers and colleagues at MIT.
Sam: [curious, leaning in] That is a significant shift. Usually, we think of library learning as taking existing code and refactoring it. If you are synthesizing them top-down, how do you keep the search space from exploding?
Alex: [analytical, clear] The key is using the corpus as a pruning filter. By treating the corpus as a set of constraints, the algorithm can aggressively discard branches that cannot possibly yield a better compression score than the current best-found abstraction.
Sam: [nodding, voice low] So it is a branch-and-bound problem. If a partial abstraction does not match enough locations to beat your current baseline, it is mathematically impossible for any refinement to be optimal.
Alex: [confirming] Exactly. This insight allows the implementation, called Stitch, to achieve three to four orders of magnitude speedup over traditional deductive methods. It turns tasks that used to crash into operations that finish in seconds.
Sam: [thoughtful] That is a massive difference. When you say it is robust to early stopping, does the quality of the library degrade linearly, or does the utility fall off a cliff?
Alex: [even pace, precise] It degrades gracefully. Because the search prioritizes branches with high upper bounds on potential utility, the algorithm finds the most valuable abstractions early. You get the bulk of the compression benefit almost immediately.
Sam: [probing] And what about variable binding? Deductive approaches often struggle with de Bruijn indices because they have to maintain semantic equivalence during every rewrite. How does Stitch handle that?
Alex: [measured] Stitch uses a modified unification procedure called lambda-aware unification. It handles index shifting and variable binding during synthesis, ensuring the abstractions are always well-formed and semantically valid.
Sam: [processing] So the mechanism is a search-based approach that uses the corpus to prune the space, while the unification handles the formal logic. [[RP_SECTION:syntactic-limitations|Syntactic Limitations]]
Sam: [reflective, grounded] It is clear that Stitch offers a significant performance leap, but we should address its limitations. The approach is fundamentally syntactic, which means it struggles to identify abstractions that are semantically equivalent but look different, such as those involving commutativity or associativity.
Alex: [analytical, measured] That is a fair critique. Without being layered on top of a deductive rewrite system, Stitch cannot see through those surface-level variations. It is essentially blind to the underlying algebraic structure unless that structure is explicitly encoded in the search.
Sam: [nodding, voice low] Exactly. And that is where the trade-off becomes visible. You gain massive speed by focusing on the syntax, but you lose the ability to discover deeper, more abstract functional patterns that a slower, deductive system might catch.
Alex: [even pace, precise] That is why the authors suggest layering Stitch on top of version spaces or e-graphs as a future path. By using a rewrite system to handle the semantic equivalences and Stitch to handle the efficient search, you might get the best of both worlds.
Sam: [thoughtful] It really changes how we think about the bottleneck of program synthesis. Instead of viewing library learning as an expensive refactoring process, we can now treat it as a top-down synthesis problem that runs in the background. [[RP_SECTION:future-synthesis-directions|Future Synthesis Directions]]
Alex: [measured, forward-looking] That opens up the possibility of dynamic, real-time library learning. Imagine an LLM that continuously refines its own domain-specific language as it generates code, enabling a self-optimizing synthesis loop that adapts to the task at hand.
Sam: [concluding, steady] This is a meaningful step forward for scalability. If you want the figures, the specific method choices, and the full list of caveats we skipped, you can generate a deep dive of this paper. The paper has the rest either way.
Alex: [warm, professional] Thanks for listening.