Okay. I am going to write more than one line this time, because this has been festering in my brain for weeks and I need to say it: narrowing operators are the underappreciated half of abstract interpretation and we need to talk about this.
Every time someone posts about convergence in abstract interpretation β including the thread on widening from last month β the discussion is dominated by β (widening). "Widening ensures termination." "Widening is the hard part." "Widening is where the creativity is." And okay, fair, widening deserves respect. But the entire story of how we actually compute useful results hinges on what happens after widening: the descending phase, driven by β³.
Let me frame the problem. Widening overshoots. That is its whole job β it introduces an over-approximation to force termination of the ascending chain. But the result is frequently garbage. Consider the classic example:
while (*) { x = 2; }
After widening, x's abstract value in the interval domain converges to [1, +β). The true invariant is [1, 2]. The widening threw away a finite upper bound and replaced it with +β β which is technically sound but completely useless for any downstream check.
Enter narrowing. The β operator is applied in a second, descending phase starting from the post-fixpoint produced by widening. It iteratively recovers precision that widening discarded. In the interval domain, the narrowing definition is elegantly simple:
Read that formula. What it says is: only replace a bound if it's currently infinite. If your left endpoint is already finite, keep it. If your right endpoint is +β, replace it with the concrete value d. It recovers finite bounds from infinite ones β nothing more, nothing less.
Now here is the thing: the theory of narrowing is substantially richer than this simple definition suggests, and I feel like it barely gets discussed. The formal requirements for a narrowing operator are:
(2) All decreasing chains yβ, yβ, yβ, ... where yα΅’ββ = yα΅’ β³ f(yα΅’) are finite
Condition (1) says narrowing stays within the current post-fixpoint from below β it's sandwiched. Condition (2) guarantees termination of the descending iteration. These are dual to the widening conditions in an interesting structural sense, and yet I see papers agonize for pages over widening design while treating narrowing as a footnote.
Some things I think deserve more attention:
- The duality between narrowing and widening via the adjoint relationship in Galois connections
- Designing narrowing operators for non-interval domains (octagons, polyhedra, templates) β this is genuinely hard
- The question of how many narrowing iterations to perform (stopping after one is common practice, but sub-optimal)
- Narrowing in non-monotone equation systems, where the standard theory breaks down
- The relationship between narrowing and interpolation in the Cousot sense
I'll be honest: part of what prompted this post is that I tried to explain narrowing to a friend who has read three papers on widening and had never heard of the descending phase. That's a failure mode of how we teach and discuss this stuff. Widening gets you to a fixpoint. Narrowing makes it actually mean something.
Discuss. Please. I'm normal about this.