Minor edits to 'lattices 2'

Signed-off-by: Danila Fedorin <danila.fedorin@gmail.com>
This commit is contained in:
Danila Fedorin 2024-05-25 20:45:19 -07:00
parent 711b01175d
commit 04f12b545d

View File

@ -16,7 +16,7 @@ of variables in a program.
At the end of that post, I introduced a source of complexity: the "full" At the end of that post, I introduced a source of complexity: the "full"
lattices that we want to use for the program analysis aren't signs or numbers, lattices that we want to use for the program analysis aren't signs or numbers,
but maps of states and variables to lattices-based states. The full lattice but maps of states and variables to lattice-based descriptions. The full lattice
for sign analysis might something in the form: for sign analysis might something in the form:
{{< latex >}} {{< latex >}}
@ -25,12 +25,12 @@ for sign analysis might something in the form:
Thus, we have to compare and find least upper bounds (e.g.) of not just Thus, we have to compare and find least upper bounds (e.g.) of not just
signs, but maps! Proving the various lattice laws for signs was not too signs, but maps! Proving the various lattice laws for signs was not too
challenging, but for for a two-level map like \(\text{info}\) above, we'd challenging, but for for a two-level map like \(\text{Info}\) above, we'd
need to do a lot more work. We need tools to build up such complicated lattices! need to do a lot more work. We need tools to build up such complicated lattices.
The way to do this, it turns out, is by using simpler lattices as building blocks. The way to do this, it turns out, is by using simpler lattices as building blocks.
To start with, let's take a look at a very simple way of combining lattices: To start with, let's take a look at a very simple way of combining lattices:
taking the Cartesian product. taking the [Cartesian product](https://mathworld.wolfram.com/CartesianProduct.html).
### The Cartesian Product Lattice ### The Cartesian Product Lattice
@ -39,12 +39,13 @@ post, each lattice comes equipped with a "least upper bound" operator \((\sqcup)
and a "greatest lower bound" operator \((\sqcap)\). Since we now have two lattices, and a "greatest lower bound" operator \((\sqcap)\). Since we now have two lattices,
let's use numerical suffixes to disambiguate between the operators let's use numerical suffixes to disambiguate between the operators
of the first and second lattice: \((\sqcup_1)\) will be the LUB operator of of the first and second lattice: \((\sqcup_1)\) will be the LUB operator of
the first lattice \(L_1\), and \((\sqcup_2)\) of the second lattice \(L_2\). the first lattice \(L_1\), and \((\sqcup_2)\) of the second lattice \(L_2\),
and so on.
Then, let's take the Cartesian product of the elements of \(L_1\) and \(L_2\); Then, let's take the Cartesian product of the elements of \(L_1\) and \(L_2\);
mathematically, we'll write this as \(L_1 \times L_2\), and in Agda, we can mathematically, we'll write this as \(L_1 \times L_2\), and in Agda, we can
just use the standard [`Data.Product`](https://agda.github.io/agda-stdlib/master/Data.Product.html) just use the standard [`Data.Product`](https://agda.github.io/agda-stdlib/master/Data.Product.html)
module. In Agda, I'll define the lattice as another [parameterized module](https://agda.readthedocs.io/en/latest/language/module-system.html#parameterised-modules). Since both \(L_1\) and \(L_2\) module. Then, I'll define the lattice as another [parameterized module](https://agda.readthedocs.io/en/latest/language/module-system.html#parameterised-modules). Since both \(L_1\) and \(L_2\)
are lattices, this parameterized module will require `IsLattice` instances are lattices, this parameterized module will require `IsLattice` instances
for both types: for both types:
@ -52,7 +53,7 @@ for both types:
Elements of \(L_1 \times L_2\) are in the form \((l_1, l_2)\), where Elements of \(L_1 \times L_2\) are in the form \((l_1, l_2)\), where
\(l_1 \in L_1\) and \(l_2 \in L_2\). The first thing we can get out of the \(l_1 \in L_1\) and \(l_2 \in L_2\). The first thing we can get out of the
way is define what it means for two such elements to be equal. Recall that way is defining what it means for two such elements to be equal. Recall that
we opted for a [custom equivalence relation]({{< relref "01_spa_agda_lattices#definitional-equality" >}}) we opted for a [custom equivalence relation]({{< relref "01_spa_agda_lattices#definitional-equality" >}})
instead of definitional equality to allow similar elements to be considered instead of definitional equality to allow similar elements to be considered
equal; we'll have to define a similar relation for our new product lattice. equal; we'll have to define a similar relation for our new product lattice.
@ -75,7 +76,7 @@ relations.
{{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 42 48 >}} {{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 42 48 >}}
In fact, defining \((\sqcup)\) and \((\sqcap)\) by simply applying the Defining \((\sqcup)\) and \((\sqcap)\) by simply applying the
corresponding operators from \(L_1\) and \(L_2\) seems quite natural as well. corresponding operators from \(L_1\) and \(L_2\) seems quite natural as well.
{{< latex >}} {{< latex >}}
@ -88,8 +89,8 @@ In Agda:
{{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 50 54 >}} {{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 50 54 >}}
All that's left is to prove the various (semi)lattice properties. Intuitively, All that's left is to prove the various (semi)lattice properties. Intuitively,
we can see that since the "combined" operator `__` just independently applies we can see that since the "combined" operator `__` just independently applies
the element operators `_≈₁_` and `_≈₂_`, as long as they are idempotent, the element operators `_⊔₁_` and `_⊔₂_`, as long as they are idempotent,
commutative, and associative, so is the "combined" operator itself. commutative, and associative, so is the "combined" operator itself.
Moreover, the proofs that `_⊔_` and `_⊓_` form semilattices are identical Moreover, the proofs that `_⊔_` and `_⊓_` form semilattices are identical
up to replacing \((\sqcup)\) with \((\sqcap)\). Thus, in Agda, we can write up to replacing \((\sqcup)\) with \((\sqcap)\). Thus, in Agda, we can write
@ -98,8 +99,9 @@ that these operators obey the semilattice laws).
{{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 56 82 >}} {{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 56 82 >}}
Similarly to the semilattice properties, proving lattice properties boils Above, I used `f₁` to stand for "either `_⊔₁_` or `_⊓₁_`", and similarly
down to applying the lattice properties of \(L_1\) and \(L_2\) to `f₂` for "either `_⊔₂_` or `_⊓₂_`". Much like the semilattice properties,
individual components. proving lattice properties boils down to applying the lattice properties of
\(L_1\) and \(L_2\) to individual components.
{{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 84 96 >}} {{< codelines "Agda" "agda-spa/Lattice/Prod.agda" 84 96 >}}