Skip to content

Prune VC content disconnected from the goal before SMT solving#407

Closed
alcides wants to merge 1 commit into
masterfrom
claude/vc-variable-usage-optimization-obn674
Closed

Prune VC content disconnected from the goal before SMT solving#407
alcides wants to merge 1 commit into
masterfrom
claude/vc-variable-usage-optimization-obn674

Conversation

@alcides

@alcides alcides commented Jun 20, 2026

Copy link
Copy Markdown
Owner

What

Optimizes verification by ensuring each VC (verification condition) handed to Z3 only contains the variables and refinements (premises) that actually mention variables used inside the obligation. Content disconnected from the goal is dropped, avoiding useless VC content and shrinking the formulas the SMT solver has to reason about.

How

A cone-of-influence pass is added to flatten in aeon/verification/smt.py. When building each canonic (flattened) constraint, _split_by_cone partitions the accumulated premises around the variables actually mentioned in the conclusion:

  • kept: variables/premises transitively connected to the goal through shared bound variables (fixpoint closure).
  • dropped: premises mentioning only variables that never reach the goal.

Only the kept variables and premises are declared in the CanonicConstraint sent to Z3.

Correctness

Dropping premises naively is unsound for completeness: a disconnected but contradictory hypothesis set can discharge a goal (e.g. proving {r: Int | false} from contradictory premises — the conclusion mentions no variables, so every premise looks "disconnected"). This is exactly what the learning_axioms refutation tests exercise.

The split is therefore made safe. Because the dropped premises share no variable with the kept side or the conclusion, the negated VC factors over disjoint variable sets — the dropped premises can only affect validity by being unsatisfiable. Before dropping them, a dedicated auxiliary Z3 solver (_premises_satisfiable) probes their satisfiability:

  • unsatisfiable → the whole obligation is vacuously valid; emit a trivially-true constraint.
  • satisfiable → safe to drop; query the smaller kept ⇒ conclusion.
  • unknown (timeout) → conservatively keep everything, unpruned.

Premises with no variables of their own (constants like a literal false) are always kept. The common case (everything connected) returns the original objects unchanged, so no extra solver work and identity-based memoization downstream keeps hitting.

Testing

  • New unit tests in tests/smt_test.py covering: unrelated variable/premise pruning, keeping connected premises, keeping contradictory unrelated premises (refutation), and not flipping a genuinely-invalid VC to valid.
  • Full suite: 1680 passed, 14 skipped.
  • mypy and ruff/format clean via pre-commit.
  • verification / list / 99problems example programs all pass.

🤖 Generated with Claude Code


Generated by Claude Code

Verification conditions accumulate every binder and refinement in scope,
even when most of them cannot affect the obligation being checked. This
adds a cone-of-influence pass in `flatten`: when building each canonic
(flattened) constraint, only the quantified variables and premises
transitively connected to the conclusion's variables (through shared
bound variables) are handed to Z3.

Dropping is done safely. Because the disconnected premises share no
variable with the kept side or the conclusion, the negated VC factors
over disjoint variable sets, so they can only affect validity by being
unsatisfiable. Before dropping them we probe their satisfiability with a
dedicated auxiliary solver: if they are contradictory the whole
obligation is vacuously valid (we emit a trivially-true constraint); if
the solver returns unknown we conservatively keep everything. This
preserves refutation-style proofs (e.g. proving `{r:Int | false}` from
contradictory hypotheses) while shrinking the formulas in the common
case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdAFspBnYJndsiUTYLyPK7
@alcides alcides closed this Jun 22, 2026
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.

2 participants