CAV 2017

Synthesis with Abstract Examples

Dana Drachsler-Cohen, Sharon Shoham, Eran Yahav

TL;DR: Standard program synthesis uses concrete examples (input/output pairs), but this limits what you can specify. This paper introduces "abstract examples" — specifications using abstract values like "positive integer" or "sorted list" — enabling synthesis of programs with richer correctness guarantees.

The Problem

Programming by example is a powerful idea: show a synthesizer a few input-output pairs, and it finds a program that matches. But concrete examples have a fundamental limitation — they are finite. You can show the synthesizer that 2 → 4, 3 → 6, and 5 → 10, and it might learn to double its input. But you cannot express "for all positive integers, the output should be positive" using finitely many concrete examples.

This is more than a theoretical nuisance. In practice, concrete examples lead to ambiguity: many programs satisfy a small set of examples, and the synthesizer has no way to distinguish between correct generalizations and coincidental fits. You need a way to express what you really mean — properties that should hold across entire classes of inputs.

The Key Idea

The key insight is to borrow from abstract interpretation, a framework for reasoning about programs over abstract domains. Instead of giving the synthesizer concrete values, you give it abstract examples: pairs of abstract values that describe properties of the input and the expected properties of the output.

For instance, rather than saying 2 → 4, you say {positive} → {positive, even}. This single abstract example captures infinitely many concrete behaviors: for any positive input, the output must be both positive and even.

The synthesizer then searches for a program whose abstract semantics satisfies all the given abstract examples. It uses the abstract transformer of each candidate program — the same machinery used in static analysis — to check whether the abstract output is consistent with the specification.

Interactive Demo: Abstract vs. Concrete

Concrete Examples: The Ambiguity Problem

Given these concrete input-output pairs, many programs are consistent:

InputOutput
24
36
510
  • x * 2?
  • x + x?
  • 2 * x?
  • x + 1?
  • x * x - x?

All five candidates match the three concrete examples. We cannot tell which is "correct."

Now add abstract constraints

Abstract Example: Filtering by Properties

Adding the abstract example positive even positive immediately rules out programs that do not guarantee these output properties:

  • x * 2positive * 2 is always even and positive
  • x + xpositive + positive is even and positive
  • 2 * x2 * positive is even and positive
  • x + 1positive + 1 is not always even
  • x * x - xnot always even (e.g. 3*3-3 = 6, but 4*4-4 = 12, 1*1-1 = 0)

3 of 5 candidates survive the abstract filter.

Try It Yourself: Pick Abstract Properties

Choose abstract properties for the input and expected output, and see which candidate programs survive.

Abstract example:

    Exercise: Progressive Refinement

    Watch how adding abstract constraints progressively narrows the candidate set. Click each step to see the effect.

      How It Works

      Abstract Interpretation Domains

      Abstract interpretation provides a principled way to approximate the behavior of a program over sets of values. An abstract domain defines which properties we track — for example, the Sign domain tracks whether a value is positive, negative, or zero; the Parity domain tracks whether a value is even or odd.

      Each operation in the programming language has an abstract transformer that describes how it maps abstract values. For instance, in the Sign domain, multiplying two positive values yields a positive value: positive * positive = positive. These transformers let us check whether a candidate program satisfies an abstract example without running it on every possible input.

      Sign Domain

      positive + positive = positive

      positive * negative = negative

      negative * negative = positive

      Tracks: positive, negative, zero

      Parity Domain

      even + even = even

      even + odd = odd

      even * any = even

      Tracks: even, odd

      Abstract Example Checking

      Given a candidate program and an abstract example, the synthesizer evaluates the program's abstract transformer on the abstract input. If the abstract output is subsumed by (i.e., at least as precise as) the required abstract output, the candidate passes. Otherwise, it is rejected.

      This is a sound check: if the abstract transformer says the output is positive, then the program truly produces a positive output for all inputs in the abstract input set. The synthesizer can therefore prune entire families of incorrect programs in a single check, rather than testing them one example at a time.

      Results

      The paper demonstrates that abstract examples lead to faster and more precise synthesis. Key findings include:

      Abstract examples bring the power of abstract interpretation to program synthesis, enabling specifications that are both more expressive and more efficient to check than traditional concrete examples.

      Drachsler-Cohen, D., Shoham, S., & Yahav, E. (2017). Synthesis with Abstract Examples. In: Majumdar, R., Kunčak, V. (eds) Computer Aided Verification. CAV 2017. Lecture Notes in Computer Science, vol 10426. Springer, Cham.