Skip to content

Quantified Aggregates (future work)

Problem

sum(lambda r: r.amount) over a quantified fact requires summing array[i].amount over i in [0, length). Z3 doesn't natively support unbounded symbolic sums.

v1 raises UnsupportedError for this case: - The selector returning a captured constant (lambda r: 1, lambda r: 5) IS supported — contribution becomes constant * product(quantifier.upper). This handles count-via-sum. - A selector depending on a bound variable (lambda r: r.amount) is rejected.

Routes

A. Z3 recursive functions

Define sum_amounts(arr, length) = If(length == 0, 0, arr[length - 1].amount + sum_amounts(arr, length - 1)). Z3 handles recursive functions via fixed-point logic, but proofs are slow and incomplete for many goals.

B. Bounded unrolling fallback

If the trusted call's postcondition gives a literal upper bound len(result) <= K, unroll the sum K times symbolically. Each term is conditional on i < length. This combines the new quantifier-aware path with bounded unrolling for aggregates specifically.

Trade-off: K becomes a knob; large K slows proofs linearly.

C. Sequence theory

Z3's Seq sort has seq.length and seq.nth but limited reasoning over predicates. Unlikely to be a general answer but worth investigating for specific aggregate shapes.

Recommendation

Start with (B) — bounded unrolling fallback. It composes naturally with the existing for-loop handler and gives a working answer for realistic K. Revisit (A) or (C) if unrolling proves insufficient.