OK I HAVE BEEN WAITING TO WRITE THIS POST FOR LIKE TWO YEARS. Galois connections are my ABSOLUTE FAVORITE concept in all of program analysis and I think they are criminally under-explained in most courses. Everyone just slaps the formal definition up and calls it a day. So let me try to actually build the intuition. (mods please sticky this, I'm begging)
THE BIG PICTURE FIRST:
A Galois connection between two posets (C, ≤) and (A, ⊑) is a pair of monotone functions:
OK you've seen that. Boring. Here's what it actually means:
α(c) is the most precise abstract element that still safely over-approximates c.
γ(a) is the largest (most general) concrete set that the abstract element a could possibly describe.
The adjunction condition says: "c fits under a's umbrella in the abstract iff c genuinely lives inside a's concretization in the concrete."
You can't fool the connection. If α says c is approximated by a, then γ had better contain c. And vice versa. It's a perfect correspondence between information loss in one direction and coverage in the other.
Let me make this super concrete with the sign domain, which is everyone's first example for a reason.
Our concrete domain: C = 𝒫(ℤ), sets of integers ordered by inclusion. Our abstract domain:
The abstraction function α works like this:
And concretization:
Now watch the adjunction property do its thing. Is α({-3, -1}) ⊑ TOP? Obviously yes, NEG ⊑ TOP. And is {-3,-1} ⊆ γ(TOP) = ℤ? Also yes! The two sides of the biconditional agree perfectly. Try any example — they always agree. That's not a coincidence. That's the Galois connection being the Galois connection. 🐾
There are two key corollaries that fall out immediately and which are the real reason we care:
Property (1) says: if you abstract a concrete value and then concretize it back, you get something at least as big — you may have lost precision. Property (2) says: if you concretize an abstract value and re-abstract it, you end up below or equal to where you started — you never gain false precision. Together, these say α and γ are each other's "best approximation" in a very precise sense.
I'll post more examples in a bit (interval domain and parity next), but first — does anyone have questions on the sign domain before I move on? Also I will fight anyone who says this is "just adjoint functors" and nothing more meaningful than that (looking at no one in particular 👀)