Skip to content

Fix enumerative search halting before budget for refined types (issue #89)#144

Merged
alcides merged 3 commits intomasterfrom
fix/issue-89-enumerative-halts
Mar 22, 2026
Merged

Fix enumerative search halting before budget for refined types (issue #89)#144
alcides merged 3 commits intomasterfrom
fix/issue-89-enumerative-halts

Conversation

@alcides
Copy link
Copy Markdown
Owner

@alcides alcides commented Mar 17, 2026

Summary

Fixes #89: the enumerative synthesizer was returning None for refined integer types like {y:Int | 0 < y && y < 100} because the grammar's unlimited-range Int literal (-100,000,000 to 100,000,000) exhausted the time budget before reaching any valid values.

  • Replace unlimited Int literal with a metahandler-based one (IntRange(-1, 256)) — the enumerative search now iterates a small, practical default range instead of 200 million integers
  • Use the refined type to generate a targeted metahandler literal — when the hole type is refined (e.g. {y:Int | 0 < y && y < 100}), an IntRange(1, 99) literal is added as a direct grammar alternative for æInt, with no refined abstract class as starting symbol
  • Fix get_core() for refined literals — returns Literal(v, base_type) so the type checker handles it correctly
  • Strip refinements from context variable types in grammar generation to avoid KeyError from mangled variable names in type_info
  • Fix SynquidSynthesizer to strip the refined type before synthesis (Synquid only handles unrefined types)

Test plan

  • New regression test test_enumerative_halts_within_budget passes: synthesizes a valid Int in (0, 100) within 0.25s budget (with a 10s SIGALRM safety guard)
  • All existing synthesis tests still pass
  • Full test suite: 184 passed, 3 skipped

🤖 Generated with Claude Code

alcides and others added 3 commits March 17, 2026 17:46
…89)

Root cause: the grammar for integer holes used an unlimited-range literal
(range -100,000,000 to 100,000,000) as the only integer production. For
{y:Int | 0 < y && y < 100}, the enumerative search exhausted the budget
iterating through negative integers before ever reaching the valid range 1–99.

Fix: replace the unlimited-range Int literal with metahandler-based literals:
- The default Int literal now uses IntRange(-1, 256) via a metahandler,
  so the enumerative search only iterates a small, practical range.
- When the synthesis target has a refined type (e.g. {y:Int | 0 < y && y < 100}),
  pass it via refined_types=True so create_literal_ref_nodes generates an
  additional metahandler literal (IntRange(1, 99)) as a direct alternative for
  æInt — no refined abstract class is used as grammar starting symbol.
- The refined literal's get_core() returns Literal(v, base_type) so the type
  checker handles it correctly.
- Context variable types are stripped of refinements in gen_grammar_nodes to
  avoid KeyErrors from mangled variable names in type_info.
- SynquidSynthesizer strips the refined type before synthesis since Synquid
  only handles unrefined types internally.
- Add regression test for the exact example from issue #89.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of stripping refinements in synthesizer.py before passing to
synthes_memory, handle RefinedType directly in synthes() by normalizing
to base type for literal generation and variable/function lookup. The
validator handles refinement checking on the synthesized terms.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When sympy's reduce_rational_inequalities encounters a non-linear
constraint (e.g. i² - x < 0, produced when a hole type depends on
a function parameter via multiplication), it raises NotImplementedError
which was re-raised and crashed the synthesis run.

Fall back to Interval(-oo, oo) in conditional_to_interval so synthesis
can continue with an unbounded range instead of crashing. The hole will
still be synthesized correctly; it just won't benefit from the tighter
literal range derived from the constraint.

Fixes the build (3.11) failure on CI triggered by
examples/synthesis/hole_refined_synthesis.ae.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@alcides
Copy link
Copy Markdown
Owner Author

alcides commented Mar 22, 2026

Found and fixed the CI failure (build (3.11)).

Root cause: examples/synthesis/hole_refined_synthesis.ae defines (?hole: {x:Int | x > 0}) * i where i is a function parameter. During synthesis grammar generation, the bounds analysis in conditional_to_interval calls sympy's reduce_rational_inequalities with the constraint i² - x < 0 (non-linear, because i is also a variable). Sympy raises NotImplementedError for non-linear inequalities, which was re-raised as a generic Exception and crashed the whole synthesis run.

Fix (aeon/synthesis/grammar/bounds.py): catch the exception in conditional_to_interval and fall back to Interval(-oo, oo) (unbounded) instead of crashing. Synthesis continues normally — it just won't benefit from a tighter literal range for that constraint.

Pushed as branch fix-enumerative-bounds-nonlinear. All 18 synthesis tests still pass.

@alcides alcides merged commit 33253cd into master Mar 22, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enumerative Algorithm halts within the time budget

1 participant