πŸ“Œ Pinned BEGINNER βœ… Answered  [BEGINNER] Explain the Interval Domain to me like I'm a kitten
πŸ‘€ Posted by KleeneCat πŸ—“οΈ 2025-11-03 02:17:44 πŸ’¬ Replies: 89 πŸ‘οΈ Views: 4,821 πŸ“‚ Forum: Static Analysis & Abstract Interpretation
🐱
Baby Kitten
NEW
Posts: 7
Joined: Oct 2025
Rep: +3
#1  Posted: 2025-11-03 02:17:44

Hewwo everyone 🐾

I just started reading about static analysis and abstract interpretation and I keep seeing "the interval domain" mentioned everywhere as like the canonical example domain but every explanation I find immediately starts talking about Galois connections and lattices and complete partial orders and my brain just turns off like a tiny sleepy kitten curled up in the sun 😴

Can someone please explain the interval abstract domain to me like I'm a small confused kitten who just wants to understand what a variable's value looks like when we're doing abstract interpretation? I understand roughly that abstract interpretation is about approximating program behavior β€” like you're too tired to track every exact value so you track something simpler β€” but the interval domain specifically confuses me.

Specifically my questions are:

  • What even IS an interval in this context?
  • How do you do arithmetic on intervals?
  • Why does it matter for analyzing programs?
  • What's "widening" and why do people talk about it with such grave expressions?

Any help is very much appreciated!! I promise I will eventually understand things and not just make confused meowing noises at the screen 🐱

"I fixed the bug by removing all the code" β€” me, every day
↩ Quote ⭐ Rep+ βš‘ Report
🐾 🐾 🐾
😺
Proof Carrying Tabby
SENIOR
Posts: 3,847
Joined: Jan 2021
Rep: +1,203
#2  Posted: 2025-11-03 02:44:11

Oh what a lovely question!! Welcome to CGPA, little KleeneCat 🐱 Don't worry, the interval domain is genuinely the most approachable abstract domain and I am going to get you there, I promise.

Step 1: What problem are we solving?

Imagine you want to analyze this tiny program:

// program.c
int x = 5; x = x + 3; // What is x here?

At runtime, x is obviously 8. Easy. But what if we have something like this:

int x = get_user_input(); // could be anything! if (x > 0) { x = x + 1; } // What is x here?

Now x could be lots of things. A static analyzer can't run the program β€” it needs to reason about all possible values without knowing the actual input. So instead of tracking the exact value of x, we track a range of possible values.

That range is an interval.

Step 2: What is an interval?

An interval [a, b] just means "the variable's value is somewhere between a and b, inclusive." That's literally it! Some special cases:

  • [5, 5] means the variable is exactly 5
  • [0, 100] means the variable is between 0 and 100
  • [-∞, +∞] means we have no idea (this is the "top" element β€” maximum uncertainty)
  • βŠ₯ (bottom) means the variable is unreachable / impossible (like after if (x > 5 && x < 0))
✨ Key Insight
We're over-approximating! If a variable's true possible values are {3, 5, 7}, we might represent that as [3, 7] β€” which includes 4 and 6 too. That's okay! We're being sound (safe), not necessarily precise. We never miss real values; we might include some fake ones.

Step 3: Arithmetic on intervals

Here's where the fun is. If I know x ∈ [2, 5] and y ∈ [1, 3], what is x + y? Well:

  • Smallest possible sum: 2 + 1 = 3
  • Largest possible sum: 5 + 3 = 8
  • So x + y ∈ [3, 8] βœ“

The general rule: [a,b] + [c,d] = [a+c, b+d]. Subtraction is [a,b] - [c,d] = [a-d, b-c] (note the flip!). Multiplication is a bit more complicated since negatives flip things around, but the idea is the same: compute all possible corners.

Step 4: Why does this help us analyze programs?

Consider a simple array access arr[i]. Is it safe? Only if 0 ≀ i < arr.length. If our analyzer can figure out that i ∈ [0, 9] and arr.length = 10, it can prove the access is safe β€” without running the program!

This is what production static analyzers do. Tools like ASTRÉE use interval analysis (and fancier relatives) to prove absence of runtime errors in safety-critical code.

I'll stop here for now so I don't overwhelm you 🐱 The widening question deserves its own post. Short answer: widening is what stops interval analysis from running forever when loops are involved. More on that soon!

πœ†x. x ∈ [0, ∞) ∩ β„€  |  she/her  |  "a lattice a day keeps the unsoundness away"
↩ Quote ⭐ Rep+ βš‘ Report
😾
Grumpy Galois Gremlin
SENIOR
Posts: 7,291
Joined: Mar 2019
Rep: +2,441
#3  Posted: 2025-11-03 03:01:58

*sighs in Galois connection*

Fine. I'll be helpful today. LatticeTabby has the core right. Let me add a few things without going full academic mode (I make no promises this lasts the whole thread).

The interval domain is formally a complete lattice (well, almost β€” it's a bit subtle with ±∞, but close enough for beginners). What that means in plain terms:

  • Ordering: [a,b] βŠ‘ [c,d] if c ≀ a and b ≀ d. Bigger intervals are "higher" in the lattice because they're less precise (they tell you less).
  • Join (βŠ”): The "least upper bound" of two intervals. [1,3] βŠ” [5,7] = [1,7]. This happens at join points in your program β€” like after an if/else where both branches could have been taken.
  • Meet (βŠ“): The "greatest lower bound." [1,7] βŠ“ [4,10] = [4,7]. Useful for narrowing down when you know a condition held.

The join at control flow merge points is really the key operation. When your program does:

if (condition) { x = 3; // x ∈ [3,3] } else { x = 7; // x ∈ [7,7] } // x ∈ [3,3] βŠ” [7,7] = [3,7]

...we join the two intervals because x could have come from either branch. We lose the information that x is either 3 or 7 but not 4, 5, or 6 β€” this is the classic imprecision of the interval domain. It can't represent disjunctions. That's a known limitation, not a bug.

Good question, OP. Don't let the formal notation scare you off β€” it's just regular math wearing a costume.

"Your proof is unsound." β€” GaloisCat, to everyone, always  |  he/him
↩ Quote ⭐ Rep+ βš‘ Report
🐈
Fixed Point Finder
MEMBER
Posts: 1,102
Joined: Aug 2022
Rep: +387
#4  Posted: 2025-11-03 03:15:22

ASCII number lines time!! I learn better visually so maybe KleeneCat does too 🐾

Here's what the interval [2, 7] looks like on the number line:

Number line: integers from -2 to 12 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 | | | | | | | | | | | | | | | [===================] ^ ^ 2 7 x ∈ [2, 7] --> "x is somewhere in that bracket"

Now here's what the join of two intervals looks like β€” this happens at if/else merge points:

x comes from branch A: x ∈ [1, 3] x comes from branch B: x ∈ [6, 9] 0 1 2 3 4 5 6 7 8 9 10 | | | | | | | | | | | [=====] [=========] Branch A Branch B After join (βŠ”): 0 1 2 3 4 5 6 7 8 9 10 | | | | | | | | | | | [===================================] [1, 9] -- covers the gap even though no real value lives in [4,5]! This is the price of intervals.

And here's meet β€” what happens when you filter by a condition like x > 4:

Before condition: x ∈ [-∞, +∞] (could be anything) Condition: x >= 3 After filtering (meet with [3, +∞]): x ∈ [-∞, +∞] βŠ“ [3, +∞] = [3, +∞] ... -1 0 1 2 3 4 5 6 ... | | | | | | | | [=============>>> 3 now guaranteed β‰₯ 3

Does this help visualize things? The interval domain is really just saying "I'll track the min and max possible value and not worry about what's in between."

my fixpoint is nap time  |  they/them  |  ascii art enjoyer since 2009
↩ Quote ⭐ Rep+ βš‘ Report
🐱
Baby Kitten
NEW
Posts: 7
Joined: Oct 2025
Rep: +3
#5  Posted: 2025-11-03 03:28:04

Oh wow this is already SO helpful, thank you all!!! 😭🐾

The ASCII number lines especially β€” that gap in the join where 4 and 5 get included even though no real value lives there, I think that's the thing that was confusing me. So the interval domain is kind of like... a lazy bounding box? Like instead of tracking exactly which values are possible, we just track "min to max" and accept that we might have some false positives?

And the βŠ₯ element (bottom) β€” that means "this program point is unreachable"? Like if I have if (x > 10 && x < 0) then the variable in that branch has a bottom interval since nothing satisfies both conditions?

Now I want to understand widening pleeease πŸ™ everyone keeps saying it with this ominous energy and I need to know what the Grave Widening Moment is about

"I fixed the bug by removing all the code" β€” me, every day
↩ Quote ⭐ Rep+ βš‘ Report
😺
Proof Carrying Tabby
SENIOR
Posts: 3,847
Joined: Jan 2021
Rep: +1,203
#6  Posted: 2025-11-03 03:47:33

Yes! Your "lazy bounding box" intuition is exactly right. And yes, βŠ₯ means unreachable β€” that's a perfect understanding πŸŽ‰

Now: The Grave Widening Momentβ„’

The problem with loops:

Consider analyzing this simple loop:

int x = 0; while (x < 10) { x = x + 1; }

When we analyze this, we repeatedly re-analyze the loop body. Let's trace what happens to x's abstract value at the loop header:

// Naive iteration without widening:
Iteration 0: x ∈ [0, 0] // just initialized Iteration 1: x ∈ [0, 1] // join with [1,1] from loop back edge Iteration 2: x ∈ [0, 2] // join with [2,2] Iteration 3: x ∈ [0, 3] Iteration 4: x ∈ [0, 4] ... Iteration k: x ∈ [0, k] // this will NEVER stabilize!

The interval keeps growing by 1 each iteration. The interval lattice has infinite ascending chains β€” there's no upper bound on how many distinct intervals you can make by incrementing the upper bound. So naive iteration does not terminate. 😱

Enter: Widening (βˆ‡)

Widening is a special operator that aggressively extrapolates to force convergence. The classic interval widening says: "if your upper bound grew between iterations, just set it to +∞ immediately. If your lower bound shrank, set it to -∞."

// Widening rule: [a,b] βˆ‡ [c,d] // If c < a: new lower bound = -∞ // Else: new lower bound = a // If d > b: new upper bound = +∞ // Else: new upper bound = b Example: [0, 0] βˆ‡ [0, 1] = [0, +∞] // upper bound grew (1 > 0), so we jump to +∞ immediately

Now let's redo the loop analysis with widening:

Iteration 0: x ∈ [0, 0] Iteration 1: [0,0] βˆ‡ [0,1] = [0, +∞] // widened! Iteration 2: [0,+∞] βˆ‡ [0,+∞] = [0, +∞] // stable! fixpoint reached βœ“

We stabilize in just 2 iterations. The trade-off: our result is [0, +∞] β€” we've lost the information that x stays below 10. That's imprecise, but it's sound (we didn't say x was in a range that excludes real values) and it terminates.

⚠️ The Widening Trade-off
Widening sacrifices precision to gain termination. It's like saying "I don't know exactly how high this number could go, so I'll just say it could go to infinity." You might then get false alarms from your analyzer β€” places that look unsafe but are actually fine β€” but you'll never miss a real bug (soundness!).

The Grave Widening Moment is real: it's when you realize your beautiful precise analysis would run forever without this blunt instrument πŸ˜”

There's also a narrowing phase that can recover some precision after widening stabilizes, but that's for another post!

πœ†x. x ∈ [0, ∞) ∩ β„€  |  she/her  |  "a lattice a day keeps the unsoundness away"
↩ Quote ⭐ Rep+ βš‘ Report
🐈
Fixed Point Finder
MEMBER
Posts: 1,102
Joined: Aug 2022
Rep: +387
#7  Posted: 2025-11-03 04:03:17

ASCII visualization of the widening sequence!! Here's what happens to x's interval at the loop header over iterations:

WITHOUT widening (runs forever β†―): Iter 0: [0,0] 0 | Iter 1: [0,1] 0 1 |--| Iter 2: [0,2] 0 2 |-----| Iter 3: [0,3] 0 3 |--------| Iter 4: [0,4] 0 4 |-----------| ... (never stops growing rightward) β†― β†― β†―
WITH widening (terminates in 2 steps βœ“): Iter 0: [0,0] 0 | Iter 1: [0,0] βˆ‡ [0,1] upper bound grew: 1 > 0, so β†’ +∞ [0, +∞] 0 +∞ |================================>>> Iter 2: [0,+∞] βˆ‡ [0,+∞] no change! FIXPOINT REACHED βœ“ Result: x ∈ [0, +∞] (conservative but sound and we're DONE)

The widening "jumps to infinity" to kill the infinite ascending chain. It's a precision-for-termination trade. 🐾

You can also think of it like a cat knocking things off a table β€” instead of carefully moving each item one centimeter at a time until it falls, widening just shoves everything off at once to get to a stable state faster πŸ±πŸ’¨

my fixpoint is nap time  |  they/them  |  ascii art enjoyer since 2009
↩ Quote ⭐ Rep+ βš‘ Report
😸
Monad Transformer Stack Overflow
MEMBER
Posts: 2,156
Joined: May 2020
Rep: +641
#8  Posted: 2025-11-03 04:22:48

Obligatory Haskell implementation because it is my civic duty and also I was already writing it during the previous posts 🐾

Here's a minimal but working interval domain with widening in Haskell:

-- Interval.hs
module Interval where import Data.Maybe -- Extended integers: -∞, n, or +∞ data Ext = NegInf | Fin Int | PosInf deriving (Eq, Ord, Show) -- The interval domain: -- Bot = βŠ₯ = unreachable / empty -- Iv lo hi = the interval [lo, hi] data Interval = Bot | Iv Ext Ext deriving (Eq, Show) -- Smart constructor (ensures lo ≀ hi) mkIv :: Ext -> Ext -> Interval mkIv lo hi | lo > hi = Bot | otherwise = Iv lo hi -- Convenience: create a finite interval from ints fromInts :: Int -> Int -> Interval fromInts a b = mkIv (Fin a) (Fin b) top :: Interval top = Iv NegInf PosInf -- Join: least upper bound of two intervals joinIv :: Interval -> Interval -> Interval joinIv Bot y = y joinIv x Bot = x joinIv (Iv a b) (Iv c d) = mkIv (min a c) (max b d) -- Widening operator βˆ‡ -- If lower bound shrank β†’ -∞ -- If upper bound grew β†’ +∞ widen :: Interval -> Interval -> Interval widen Bot y = y widen x Bot = x widen (Iv a b) (Iv c d) = let lo = if c < a then NegInf else a hi = if d > b then PosInf else b in Iv lo hi -- Addition of intervals addExt :: Ext -> Ext -> Ext addExt NegInf _ = NegInf addExt _ NegInf = NegInf addExt PosInf _ = PosInf addExt _ PosInf = PosInf addExt (Fin x) (Fin y) = Fin (x + y) addIv :: Interval -> Interval -> Interval addIv Bot _ = Bot addIv _ Bot = Bot addIv (Iv a b) (Iv c d) = mkIv (addExt a c) (addExt b d) -- Simulate analyzing: x = 0; while (x < 10) { x = x + 1; } -- Using widening to find a fixpoint analyzeLoop :: Interval analyzeLoop = go (fromInts 0 0) where go x = let x' = joinIv (fromInts 0 0) (addIv x (fromInts 1 1)) xw = widen x x' in if xw == x then x else go xw -- ghci> analyzeLoop -- Iv (Fin 0) PosInf β†’ x ∈ [0, +∞]

The widen function is the heart of it. It checks: did the lower bound get smaller? Jump to -∞. Did the upper bound get bigger? Jump to +∞. This ensures the sequence terminates in a bounded number of steps.

You can also do narrowing after widening to refine the result. But that's a longer story β€” let me know if you want a follow-up!

(Note: this is a pedagogical implementation. Real-world analyzers have much more complexity around conditionals, memory, structs, etc.)

βˆ€ problems βˆƒ monad transformer  |  she/her  |  cabal install everything
↩ Quote ⭐ Rep+ βš‘ Report
πŸ™€
Category Catastrophe
CAT THEORY
Posts: 4,502
Joined: Nov 2018
Rep: +999
#9  Posted: 2025-11-03 05:01:55

I have been watching this thread with increasing impatience because no one has said the words Galois connection yet and I physically cannot allow that to continue.

⚠️ MOD NOTE: AbstractKitty has been warned about the "going too deep for beginner threads" rule but we all know it won't stick β€” LatticeTabby

Okay so. The REAL reason the interval domain works is because there is a formal relationship between the concrete domain (the actual sets of possible values) and the abstract domain (the intervals). This relationship is called a Galois connection.

You have two functions:

  • Ξ± (abstraction): takes a set of concrete integers and gives you the tightest interval that contains them. E.g. Ξ±({1,3,5,7}) = [1,7]
  • Ξ³ (concretization): takes an interval and gives you the set of integers it represents. E.g. Ξ³([2,5]) = {2,3,4,5}

These form a Galois connection if for all concrete sets S and abstract intervals I:

Ξ±(S) βŠ‘ I ⟺ S βŠ† Ξ³(I) -- "The abstraction of S is below I in the abstract domain -- iff S is contained in what I concretizes to"

This is the formal guarantee of soundness. If your abstract transformers (the functions that compute new intervals) respect this Galois connection, then your analysis is provably sound β€” it never misses real program behaviors.

Now. The category theory angle: a Galois connection between two posets (P, ≀) and (Q, ≀) is the same thing as an adjunction between them viewed as categories! The abstraction function Ξ± is the left adjoint and the concretization Ξ³ is the right adjoint. The unit of the adjunction gives you S βŠ† Ξ³(Ξ±(S)) (you always have at least as much when you round-trip) and the counit gives you Ξ±(Ξ³(I)) βŠ‘ I (abstracting the concretization is at most I).

The interval domain itself can be seen as the free bounded-complete partial order on the natural numbers via a certain completion process known as the...

GaloisCat (in the mod channel):
AbstractKitty please for the love of all that is denotational do NOT explain the ideal completion to a kitten who just learned what an interval is

...I will table the ideal completion for another thread. The point is: the interval domain has beautiful categorical foundations and the Galois connection is why it works. The "over-approximation is okay" fact is the counit of the adjunction. That's it. That's the whole secret.

KleeneCat: you don't need to understand any of this paragraph yet! But come back to it when you've read the Cousot & Cousot 1977 paper 🐾

every diagram commutes if you squint hard enough  |  they/them  |  Yoneda enjoyer
↩ Quote ⭐ Rep+ βš‘ Report
😾
Grumpy Galois Gremlin
SENIOR
Posts: 7,291
Joined: Mar 2019
Rep: +2,441
#10  Posted: 2025-11-03 05:14:22
AbstractKitty wrote:
The interval domain itself can be seen as the free bounded-complete partial order on the natural numbers via a certain completion process known as the...

I literally typed that mod note in real time as I watched them compose that post.

KleeneCat: AbstractKitty's Galois connection paragraph is actually correct and useful, even if the category theory tangent is not something you need right now. The Ξ±/Ξ³ pair is worth understanding once you've got the basics.

The short version of what AbstractKitty said: the reason it's "okay" to over-approximate (to say [3,7] when the real values are {3,5,7}) is that there's a formal guarantee. Our abstract analysis is a safe approximation. We might report false alarms (flag safe code as potentially unsafe) but we will never miss a real bug. This property is called soundness and it's the core promise of abstract interpretation.

Also to answer your question from post #5: yes, βŠ₯ represents exactly that β€” an impossible/unreachable state. If the analyzer computes βŠ₯ at some program point, it means "we've proven this point can never be reached." That's actually useful information!

Good thread. Welcome to the dark side of formal methods, KleeneCat. We have meowing and Haskell.

"Your proof is unsound." β€” GaloisCat, to everyone, always  |  he/him
↩ Quote ⭐ Rep+ βš‘ Report
😺
Proof Carrying Tabby
SENIOR
Posts: 3,848
Joined: Jan 2021
Rep: +1,209
#11  Posted: 2025-11-03 05:38:44

Great thread everyone 🐾 Let me write a summary for KleeneCat and anyone else who finds this via search:

πŸ“‹ TL;DR Summary β€” The Interval Domain

What is it?
The interval domain represents a numeric variable's possible values as a range [lo, hi]. It's an abstract domain β€” a simplified way to represent sets of program states for static analysis.

Key elements:
β€’ [a, b] β€” variable is between a and b
β€’ βŠ₯ (Bot) β€” unreachable program point
β€’ [-∞, +∞] (Top) β€” completely unknown value

Key operations:
β€’ Join (βŠ”): merge intervals at control-flow join points β†’ take outer bounds
β€’ Meet (βŠ“): intersect intervals when a condition is known β†’ take inner bounds
β€’ Transfer functions: add, subtract, multiply intervals through program statements
β€’ Widening (βˆ‡): aggressive jump to ±∞ to force fixpoint convergence on loops

Why does it work?
The interval domain is connected to the concrete (exact) domain via a Galois connection (Ξ±, Ξ³). This guarantees soundness: the analysis can over-approximate but never under-approximate. False alarms possible; missed bugs: never.

When to use it?
When you want to prove things like "array index i is always in range [0, n-1]" or "no integer overflow possible" β€” any property that can be checked by knowing numeric ranges.

Limitations?
Intervals can't represent disjunctions: if x is either 3 or 7, you get [3,7] (includes the gap). For that, you'd need a more expressive domain (e.g., octagons, polyhedra, or disjunctive completion).

Marking this thread as βœ… Answered! KleeneCat, read the linked resources below and feel free to ask follow-up questions β€” this community loves a curious kitten 🐱

Suggested next reads:

πœ†x. x ∈ [0, ∞) ∩ β„€  |  she/her  |  "a lattice a day keeps the unsoundness away"
↩ Quote ⭐ Rep+ βš‘ Report
🐱
Baby Kitten
NEW
Posts: 8
Joined: Oct 2025
Rep: +3
#12  Posted: 2025-11-03 06:02:11

I UNDERSTAND THE INTERVAL DOMAIN!!!! πŸŽ‰πŸΎπŸŽ‰

Okay so let me check my understanding one more time:

  • An interval [a,b] is just a bounding box for all possible values of a variable βœ“
  • We over-approximate (safe but imprecise) by design β€” this is soundness βœ“
  • βŠ₯ = unreachable, [-∞,+∞] = total ignorance βœ“
  • Loops are a problem because the interval keeps growing forever without help βœ“
  • Widening kicks the interval up to ±∞ aggressively to force the analysis to terminate in finite steps βœ“
  • The Galois connection (Ξ±, Ξ³) is what makes it all formally correct βœ“ (I will understand this better later)

This community is amazing. GaloisCat being patient, LatticeTabby's beautiful explanations, FixpointFeline's ASCII art (I literally printed it out), MeownadTransformer's Haskell code which I am actually going to run, and AbstractKitty going full galaxy brain in a beginner thread which I secretly found very cool even if I'm not ready for it yet 🐱

I'm going to go read the Cousot paper now and come back when my brain has finished loading. Thank you all so much!! πŸ’œπŸ©·

"I fixed the bug by removing all the code" β€” me, every day
↩ Quote ⭐ Rep+ βš‘ Report
🐾 🐾 🐾
Thread continues β€” 77 more replies on pages 2–4. Topics include: narrowing in depth, interval analysis in LLVM/IKOS, relational extensions, and a 40-post argument between GaloisCat and AbstractKitty about whether widening is "cheating."

✏️ Post a Reply

πŸ’‘ Please keep it relevant and constructive. Forum Rules apply.
πŸ“‚ Related Threads in Static Analysis & Abstract Interpretation
● The Sign Domain β€” even simpler, good warm-up
42 replies Β· LatticeTabby
● Galois Connections, Explained Gently
61 replies Β· AbstractKitty
● Widening & Narrowing: Deep Dive
88 replies Β· GaloisCat, MeownadTransformer
● Intervals vs Octagons vs Polyhedra
37 replies Β· FixpointFeline
● Cousot & Cousot 1977 Paper Reading Group
203 replies Β· ongoing
● Tools: IKOS, Frama-C, AstrΓ©e β€” which one?
55 replies Β· GaloisCat
🟒 Users online: LatticeTabby, FixpointFeline, AbstractKitty, MeownadTransformer, KleeneCat  |  12 guests viewing this thread