haskellify finite-field.3
This commit is contained in:
parent
8d14c5b414
commit
91cfd2397a
1
posts/finite-field/3/Previous.hs
Symbolic link
1
posts/finite-field/3/Previous.hs
Symbolic link
@ -0,0 +1 @@
|
||||
../2/Previous.hs
|
||||
@ -5,9 +5,8 @@ description: |
|
||||
format:
|
||||
html:
|
||||
html-math-method: katex
|
||||
jupyter: python3
|
||||
date: "2024-02-03"
|
||||
date-modified: "2025-07-16"
|
||||
date-modified: "2025-08-04"
|
||||
categories:
|
||||
- algebra
|
||||
- finite field
|
||||
@ -15,26 +14,64 @@ categories:
|
||||
---
|
||||
|
||||
<style>
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
.orange {
|
||||
color: orange;
|
||||
}
|
||||
.yellow {
|
||||
color: yellow;
|
||||
}
|
||||
.green {
|
||||
color: green;
|
||||
}
|
||||
.blue {
|
||||
color: blue;
|
||||
}
|
||||
.purple {
|
||||
color: purple;
|
||||
.narrow {
|
||||
max-width: 512px;
|
||||
}
|
||||
</style>
|
||||
|
||||
```{haskell}
|
||||
--| echo: false
|
||||
|
||||
:l Previous.hs
|
||||
|
||||
import Data.Array (ixmap, bounds, (!))
|
||||
import Data.List (intercalate)
|
||||
import IHaskell.Display (markdown)
|
||||
|
||||
import Previous (
|
||||
Matrix(Mat, unMat), Polynomial(Poly, coeffs),
|
||||
asPoly, evalPoly, synthDiv,
|
||||
companion, zero, eye, determinant
|
||||
)
|
||||
|
||||
-- Explicit Matrix operations
|
||||
(|+|) :: Num a => Matrix a -> Matrix a -> Matrix a
|
||||
(|+|) = (+)
|
||||
|
||||
(|*|) :: Num a => Matrix a -> Matrix a -> Matrix a
|
||||
(|*|) = (*)
|
||||
|
||||
-- Original determinant implementation, instead of the imported one based on Faddeev-Leverrier
|
||||
laplaceDet :: (Num a, Eq a) => Matrix a -> a
|
||||
laplaceDet (Mat xs) = determinant' xs where
|
||||
-- Evaluate (-1)^i without repeated multiplication
|
||||
parity i = if even i then 1 else -1
|
||||
-- Map old array addresses to new ones when eliminating row 0, column i
|
||||
rowMap i (x,y) = (x+1, if y >= i then y+1 else y)
|
||||
-- Recursive determinant Array
|
||||
determinant' xs
|
||||
-- Base case: 1x1 matrix
|
||||
| n == 0 = xs!(0,0)
|
||||
-- Sum of cofactor expansions
|
||||
| otherwise = sum $ map cofactor [0..n] where
|
||||
-- Produce the cofactor of row 0, column i
|
||||
cofactor i
|
||||
| xs!(0,i) == 0 = 0
|
||||
| otherwise = (parity i) * xs!(0,i) * determinant' (minor i)
|
||||
-- Furthest extent of the bounds, i.e., the size of the matrix
|
||||
(_,(n,_)) = bounds xs
|
||||
-- Build a new Array by eliminating row 0 and column i
|
||||
minor i = ixmap ((0,0),(n-1,n-1)) (rowMap i) xs
|
||||
|
||||
-- Convert matrix to LaTeX string
|
||||
texifyMatrix' f mat = surround mat' where
|
||||
mat' = intercalate " \\\\ " $ map (intercalate " & " . map f) $
|
||||
fromMatrix mat
|
||||
surround = ("\\left( \\begin{matrix}" ++) . (++ "\\end{matrix} \\right)")
|
||||
|
||||
texifyMatrix = texifyMatrix' show
|
||||
```
|
||||
|
||||
|
||||
In the [previous post](../2), we focused on constructing finite fields using *n*×*n* matrices.
|
||||
These matrices came from from primitive polynomials of degree *n* over GF(*p*),
|
||||
@ -59,12 +96,12 @@ $$
|
||||
0 & 0 \\
|
||||
0 & 0
|
||||
\end{matrix}\right)
|
||||
\quad
|
||||
~~
|
||||
1 \mapsto \left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 1
|
||||
\end{matrix}\right) = I
|
||||
\quad
|
||||
~~
|
||||
\alpha \mapsto \left(\begin{matrix}
|
||||
0 & 1 \\
|
||||
1 & 1
|
||||
@ -93,9 +130,9 @@ $$
|
||||
In the images of *f*, the zero matrix has determinant 0 and all other elements have determinant 1.
|
||||
Therefore, the product of any two nonzero matrices always has determinant 1,
|
||||
and a nonzero determinant means the matrix is invertible.
|
||||
This means that the non-zero elements of the field form their own group with respect to multiplication.
|
||||
Per the definition of the field, the non-zero elements form a group with respect to multiplication.
|
||||
Here, they form a cyclic group of order 3, since *C*~*p*~^3^ = *I* mod 2.
|
||||
This is also true using symbols, and we've already agreed that *α*^3^ = 1.
|
||||
This is also true using symbols, since *α*^3^ = 1.
|
||||
|
||||
|
||||
### Other Matrices
|
||||
@ -109,47 +146,51 @@ $$
|
||||
\#\{a_{ij} = 1\} & \det = 0 & \det = 1
|
||||
\\ \hline
|
||||
1 &
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
0 & 1 \\
|
||||
0 & 0
|
||||
\end{matrix}\right)
|
||||
\quad
|
||||
~~
|
||||
\left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 0
|
||||
\end{matrix}\right)
|
||||
\quad
|
||||
~~
|
||||
\left(\begin{matrix}
|
||||
0 & 0 \\
|
||||
0 & 1
|
||||
\end{matrix}\right)
|
||||
\quad
|
||||
~~
|
||||
\left(\begin{matrix}
|
||||
0 & 0 \\
|
||||
1 & 0
|
||||
\end{matrix}\right)
|
||||
\\
|
||||
2 &
|
||||
2 &
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
1 & 1 \\
|
||||
0 & 0
|
||||
\end{matrix}\right)
|
||||
\quad
|
||||
~~
|
||||
\left(\begin{matrix}
|
||||
0 & 0 \\
|
||||
1 & 1
|
||||
\end{matrix}\right)
|
||||
\quad
|
||||
~~
|
||||
\left(\begin{matrix}
|
||||
0 & 1 \\
|
||||
0 & 1
|
||||
\end{matrix}\right)
|
||||
\quad
|
||||
~~
|
||||
\left(\begin{matrix}
|
||||
1 & 1 \\
|
||||
0 & 0
|
||||
\end{matrix}\right)
|
||||
& \textcolor{red}{
|
||||
&
|
||||
\scriptsize
|
||||
\textcolor{red}{
|
||||
\left(\begin{matrix}
|
||||
0 & 1 \\
|
||||
1 & 0
|
||||
@ -157,13 +198,14 @@ $$
|
||||
}
|
||||
\\
|
||||
3 & &
|
||||
\scriptsize
|
||||
\textcolor{red}{
|
||||
\left(\begin{matrix}
|
||||
1 & 1 \\
|
||||
0 & 1
|
||||
\end{matrix}\right)
|
||||
}
|
||||
\quad
|
||||
~~
|
||||
\textcolor{red}{
|
||||
\left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
@ -172,6 +214,7 @@ $$
|
||||
}
|
||||
\\
|
||||
4 &
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
1 & 1 \\
|
||||
1 & 1
|
||||
@ -184,12 +227,15 @@ The matrices in the right column (in red) have determinant 1, which means they c
|
||||
This forms a larger group, of which our field's multiplication group is a subgroup.
|
||||
However, it is *not* commutative, since matrix multiplication is not commutative in general.
|
||||
|
||||
The group of all six matrices of determinant 1 is called the
|
||||
The group of all six matrices with nonzero determinant is called the
|
||||
[*general linear group*](https://en.wikipedia.org/wiki/General_linear_group)
|
||||
of degree 2 over GF(2), written GL(2, 2).
|
||||
of degree 2 over GF(2), written[^1] GL(2, 2).
|
||||
We can sort the elements into classes by their order, or the number of times we have
|
||||
to multiply them before getting to the identity matrix (mod 2):
|
||||
|
||||
[^1]: Unfortunately, it's rather easy to confuse "GF" with "GL".
|
||||
Remember that "F" is for "field", with the former standing for "Galois field".
|
||||
|
||||
$$
|
||||
\begin{array}{}
|
||||
\text{Order 1} & \text{Order 2} & \text{Order 3}
|
||||
@ -232,10 +278,10 @@ $$
|
||||
|
||||
If you've studied enough group theory, you know that there are two groups of order 6:
|
||||
the cyclic group of order 6, *C*~6~, and the symmetric group on three elements, *S*~3~.
|
||||
Since the former group has order-6 elements, this group must be isomorphic to the latter.
|
||||
Since the former group has order-6 elements, but none of these matrices are of order 6,
|
||||
the matrix group must be isomorphic to the latter.
|
||||
Since the group is small, it's not too difficult to construct an isomorphism between the two.
|
||||
Writing the elements of *S*~3~ in [cycle notation](), we have:
|
||||
<!-- TODO: permutations link -->
|
||||
Writing the elements of *S*~3~ in [cycle notation](/posts/permutations/1/), we have:
|
||||
|
||||
$$
|
||||
\begin{gather*}
|
||||
@ -293,11 +339,9 @@ Haskell implementation of GL and SL for prime fields
|
||||
This implementation will be based on the `Matrix` type from the first post.
|
||||
Assume we have already defined matrix multiplication and addition.
|
||||
|
||||
```{.haskell}
|
||||
data Matrix a = Mat { unMat :: Array (Int, Int) a }
|
||||
|
||||
-- instance Functor Matrix
|
||||
-- instance Num a => Num (Matrix a)
|
||||
```{haskell}
|
||||
import Data.Array (listArray, bounds, elems)
|
||||
import Data.List (unfoldr)
|
||||
|
||||
-- Partition a list into lists of length n
|
||||
reshape :: Int -> [a] -> [[a]]
|
||||
@ -316,27 +360,29 @@ fromMatrix :: Matrix a -> [[a]]
|
||||
fromMatrix (Mat m) = let (_,(_,n)) = bounds m in reshape (n+1) $ elems m
|
||||
```
|
||||
|
||||
With helper functions out of the way, we can move on to generating all matrices (mod *n*)
|
||||
before filtering for matrices with nonzero determinant (in the case of GL) and determinant 1
|
||||
With helper functions out of the way, we can move on to generating all matrices (mod *n*).
|
||||
Then, we filter for matrices with nonzero determinant (in the case of GL) and determinant 1
|
||||
(in the case of SL).
|
||||
|
||||
```{.haskell}
|
||||
allMatrices :: Int -> Int -> Matrix Int
|
||||
```{haskell}
|
||||
import Control.Monad (replicateM)
|
||||
|
||||
-- All m x m matrices (mod n)
|
||||
allMatrices m n = map toMatrix $ sequence $ replicate m vectors where
|
||||
allMatrices :: Int -> Int -> [Matrix Int]
|
||||
allMatrices m n = map toMatrix $ replicateM m vectors where
|
||||
-- Construct all vectors mod n using base-n expansions and padding
|
||||
vectors = [pad $ coeffs $ asPoly n l | l <- [1..n^m-1]]
|
||||
-- Pad xs to length m with zero
|
||||
pad xs = xs ++ replicate 0 (m - length xs)
|
||||
pad xs = xs ++ replicate (m - length xs) 0
|
||||
|
||||
-- All matrices, but paired with their determinants
|
||||
matsWithDets :: Int -> Int -> [(Matrix Int, Int)]
|
||||
matsWithDets m n = map (\x -> (x, determinant x `mod` n)) $ allMatrices m n
|
||||
|
||||
-- Nonzero determinants
|
||||
mGL m n = map fst $ filter (\(x,d) -> d /= 0) $ matsWithDets' m n
|
||||
mGL m n = map fst $ filter (\(x,d) -> d /= 0) $ matsWithDets m n
|
||||
-- Determinant is 1
|
||||
mSL m n = map fst $ filter (\(x,d) -> d == 1) $ matsWithDets' m n
|
||||
mSL m n = map fst $ filter (\(x,d) -> d == 1) $ matsWithDets m n
|
||||
```
|
||||
</details>
|
||||
|
||||
@ -346,13 +392,14 @@ mSL m n = map fst $ filter (\(x,d) -> d == 1) $ matsWithDets' m n
|
||||
Another important matrix group is the
|
||||
[*projective general linear group*](https://en.wikipedia.org/wiki/Projective_linear_group),
|
||||
PGL(*n*, *K*).
|
||||
In this group, two matrices are considered equal if one is a scalar multiple of the other.
|
||||
Equivalently, the elements *are* these equivalence classes, and the product of two classes is
|
||||
the set of all possible products of items from one class with items from the other.
|
||||
|
||||
In this group, two matrices are considered equal if one is a scalar multiple of the other[^2].
|
||||
Both this and the determinant 1 constraint can apply at the same time,
|
||||
forming the *projective special linear group*, PSL(*n*, *K*).
|
||||
|
||||
[^2]: Equivalently, the elements *are* these equivalence classes.
|
||||
The product of two classes is the set of all possible products between the two classes,
|
||||
which is another class.
|
||||
|
||||
For GF(2), all of these groups are the same, since the only nonzero determinant and scalar multiple is 1.
|
||||
Therefore, it's beneficial to contrast SL and PGL with another example.
|
||||
|
||||
@ -369,23 +416,27 @@ $$
|
||||
\large \text{GL}(2, 5)
|
||||
\\
|
||||
\underset{\det = 4}{
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
0 & 1 \\
|
||||
1 & 1
|
||||
\end{matrix} \right) },
|
||||
\textcolor{red}{ \underset{\det = 1}{
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
0 & 2 \\
|
||||
2 & 2
|
||||
\end{matrix} \right)
|
||||
}},
|
||||
\underset{\det = 2}{
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 2
|
||||
\end{matrix} \right)
|
||||
},
|
||||
\underset{\det = 3}{
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
2 & 0 \\
|
||||
0 & 4
|
||||
@ -398,6 +449,7 @@ $$
|
||||
\large \text{PGL}(2,5)
|
||||
\\
|
||||
\underset{\det = 1, ~4}{
|
||||
\scriptsize
|
||||
\textcolor{red}{\left\{
|
||||
\left(\begin{matrix}
|
||||
0 & 1 \\
|
||||
@ -412,6 +464,7 @@ $$
|
||||
}}
|
||||
\\
|
||||
\underset{\det = 2, ~ 3}{
|
||||
\scriptsize
|
||||
\left\{ \left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 2
|
||||
@ -432,11 +485,13 @@ $$
|
||||
\large \text{SL}(2,5)
|
||||
\\
|
||||
\textcolor{red}{
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
0 & 2 \\
|
||||
2 & 2
|
||||
\end{matrix} \right)
|
||||
},
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
0 & 3 \\
|
||||
3 & 3
|
||||
@ -448,6 +503,7 @@ $$
|
||||
\large \text{PSL}(2,5)
|
||||
\\
|
||||
\textcolor{red}{ \left\{
|
||||
\scriptsize
|
||||
\left(\begin{matrix}
|
||||
0 & 2 \\
|
||||
2 & 2
|
||||
@ -463,32 +519,30 @@ $$
|
||||
\end{matrix}
|
||||
$$
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Haskell implementation of PGL and PSL for prime fields
|
||||
</summary>
|
||||
PGL and PSL require special equality.
|
||||
It's certainly possible to write a definition which makes the classes explicit, as its own new type.
|
||||
We could then define equality on this type through `Eq`.
|
||||
This is rather inefficient, though, so I'll choose to work with the representatives instead.
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
--| code-summary: "Haskell implementation of PGL and PSL for prime fields"
|
||||
|
||||
```{.haskell}
|
||||
import Data.List (nubBy)
|
||||
|
||||
scalarTimes :: Int -> Int -> Matrix Int -> Matrix Int
|
||||
-- PGL and PSL require special equality.
|
||||
-- It's certainly possible to write a definition which makes the classes explicit, as its own new type.
|
||||
-- We could then define equality on this type through `Eq`.
|
||||
-- This is rather inefficient, though, so I'll choose to work with the representatives instead.
|
||||
|
||||
-- Scalar-multiply a matrix (mod p)
|
||||
scalarTimes :: Int -> Int -> Matrix Int -> Matrix Int
|
||||
scalarTimes n k = fmap ((`mod` n) . (*k))
|
||||
|
||||
projEq :: Int -> Matrix Int -> Matrix Int -> Bool
|
||||
-- Construct all scalar multiples mod n, then check if ys is any of them.
|
||||
-- This is ludicrously inefficient, and only works for fields.
|
||||
projEq :: Int -> Matrix Int -> Matrix Int -> Bool
|
||||
projEq n xs ys = ys `elem` [scalarTimes n k xs | k <- [1..n-1]]
|
||||
|
||||
-- Strip out duplicates in GL and SL with projective equality
|
||||
mPGL m n = nubBy (projEq n) $ mGL m n
|
||||
mPSL m n = nubBy (projEq n) $ mSL m n
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
### Exceptional Isomorphisms
|
||||
@ -526,10 +580,10 @@ Within the group, there are three kinds of elements:
|
||||
(or more precisely, 1/2 of a turn) about an edge
|
||||
- 5-cycles, such as *b* = (1 2 3 4 5)
|
||||
- This corresponds to a 72 degree rotation (1/5 of a turn)
|
||||
around the center of a face
|
||||
around a vertex
|
||||
- 3-cycles, such as *ab* = (2 4 5)
|
||||
- This corresponds to a 120 degree rotation (1/3 of a turn)
|
||||
around a vertex
|
||||
around the center of a face
|
||||
|
||||
It happens to be the case that all elements of the group can be expressed
|
||||
as a product between *a* and *b* -- they generate the group.
|
||||
@ -541,137 +595,82 @@ To create a correspondence with PSL(2, 5), we need to identify permutations with
|
||||
Obviously, the identity permutation goes to the identity matrix.
|
||||
Then, since *a* and *b* generate the group, we can search for two matrices which
|
||||
obey the same relations (under projective equality, since we're working in PSL).
|
||||
One such correspondence is:
|
||||
|
||||
$$
|
||||
\begin{array}{}
|
||||
\begin{gather*}
|
||||
A = \left(\begin{matrix}
|
||||
1 & 1 \\
|
||||
3 & 4
|
||||
\end{matrix} \right)
|
||||
\qquad
|
||||
A^2 = \left(\begin{matrix}
|
||||
4 & 0 \\
|
||||
0 & 4
|
||||
\end{matrix}\right) =
|
||||
4 \left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 1
|
||||
\end{matrix}\right)
|
||||
\qquad
|
||||
\end{gather*}
|
||||
\\ ~ \\ \hline \\
|
||||
\begin{gather*}
|
||||
B = \left(\begin{matrix}
|
||||
0 & 2 \\
|
||||
2 & 2
|
||||
\end{matrix} \right)
|
||||
\qquad
|
||||
B^2 = \left(\begin{matrix}
|
||||
4 & 4 \\
|
||||
4 & 3
|
||||
\end{matrix}\right)
|
||||
\qquad
|
||||
B^3 = \left(\begin{matrix}
|
||||
3 & 1 \\
|
||||
1 & 4
|
||||
\end{matrix}\right)
|
||||
\\
|
||||
B^4 = \left(\begin{matrix}
|
||||
2 & 3 \\
|
||||
3 & 0
|
||||
\end{matrix}\right)
|
||||
\qquad
|
||||
B^5 = \left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 1
|
||||
\end{matrix}\right)
|
||||
\end{gather*}
|
||||
\\ ~ \\ \hline \\
|
||||
\begin{gather*}
|
||||
(AB) = \left(\begin{matrix}
|
||||
2 & 4 \\
|
||||
3 & 4
|
||||
\end{matrix} \right)
|
||||
\qquad
|
||||
(AB)^2 = \left(\begin{matrix}
|
||||
1 & 4 \\
|
||||
3 & 3
|
||||
\end{matrix}\right)
|
||||
\qquad
|
||||
(AB)^3 = \left(\begin{matrix}
|
||||
4 & 0 \\
|
||||
0 & 4
|
||||
\end{matrix}\right)
|
||||
\end{gather*} =
|
||||
4 \left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 1
|
||||
\end{matrix}\right)
|
||||
\end{array}
|
||||
$$
|
||||
Fortunately, we have a computer, so we can search for candidates rather quickly.
|
||||
First, let's note a matrix *B* which is cyclic of order 5 to correspond with *b*:
|
||||
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
--| code-summary: "Haskell implementation of finding candidates for B"
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Haskell implementation using B as a generator to find candidates for A
|
||||
</summary>
|
||||
|
||||
```{.haskell}
|
||||
orderWith :: Eq a => (a -> a -> a) -> (a -> Bool) -> a -> Int
|
||||
-- Repeatedly apply f to p, until the predicate z
|
||||
-- (usually equality to some quantity) becomes True.
|
||||
-- Get the length of the resulting list
|
||||
orderWith :: Eq a => (a -> a -> a) -> (a -> Bool) -> a -> Int
|
||||
orderWith f z p = (+1) $ length $ takeWhile (not . z) $ iterate (f p) p
|
||||
|
||||
-- Order with respect to PSL(2, 5): using matrix multiplication (mod 5)
|
||||
-- and projective equality to the identity matrix
|
||||
orderPSL25 = orderWith (\x -> fmap (`mod` 5) . (x |*|))) (projEq 5 $ eye 2)
|
||||
orderPSL25 = orderWith (\x -> fmap (`mod` 5) . (x |*|)) (projEq 5 $ eye 2)
|
||||
|
||||
-- Only order 2 elements of PSL(2, 5)
|
||||
psl25_order2 = filter ((==2) . orderPSL25) $ mPSL 2 5
|
||||
-- Only order 5 elements of PSL(2, 5)
|
||||
psl25_order5 = filter ((==5) . orderPSL25) $ mPSL 2 5
|
||||
|
||||
markdown $ ("$$B = " ++) $ (++ "... $$") $ intercalate " ~,~ " $
|
||||
take 5 $ map texifyMatrix psl25_order5
|
||||
```
|
||||
|
||||
Arbitrarily, let's pick the last entry on this list.
|
||||
Now, we can search for order-2 elements in PSL(2, 5) whose product with *B* has order 3.
|
||||
This matrix (*A*) matches exactly with *a* in *A*~5~.
|
||||
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
--| code-summary: "Haskell implementation using B as a generator to find candidates for A"
|
||||
|
||||
-- Start with B as a generator
|
||||
psl25_gen_B = toMatrix [[0,2],[2,2]]
|
||||
|
||||
-- Find an order 2 element whose product with `psl25_gen_B` has order 3
|
||||
psl25_gen_A_candidates = filter ((==3) . orderPSL25 . (psl25_gen_B |*|)) \
|
||||
psl25_order2
|
||||
-- Only order 2 elements of PSL(2, 5)
|
||||
psl25_order2 = filter ((==2) . orderPSL25) $ mPSL 2 5
|
||||
|
||||
-- Candidate matrices:
|
||||
--
|
||||
-- [1,1]
|
||||
-- [3,4]
|
||||
--
|
||||
-- [1,3]
|
||||
-- [1,4]
|
||||
--
|
||||
-- [2,0]
|
||||
-- [0,3]
|
||||
--
|
||||
-- [2,0]
|
||||
-- [4,3]
|
||||
--
|
||||
-- [2,4]
|
||||
-- [0,3]
|
||||
-- Find an order 2 element whose product with `psl25_gen_B` has order 3
|
||||
psl25_gen_A_candidates = filter ((==3) . orderPSL25 . (psl25_gen_B |*|))
|
||||
psl25_order2
|
||||
|
||||
markdown $ ("$$A = " ++) $ (++ "$$") $ intercalate " ~,~ " $
|
||||
map texifyMatrix psl25_gen_A_candidates
|
||||
```
|
||||
|
||||
If you're unsatisfied with starting from *B*, realize that we could have filtered out
|
||||
only the order 5 elements of PSL(2, 5) (`filter ((==5) . psl25Order) $ mPSL 2 5`),
|
||||
and picked any element from this list to start.
|
||||
</details>
|
||||
Again, arbitrarily, we'll pick the last entry from this list.
|
||||
Let's also peek at what the matrix *AB* looks like.
|
||||
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
|
||||
psl25_gen_AB = (`mod` 5) <$> (psl25_gen_A_candidates !! 4) |*| psl25_gen_B
|
||||
|
||||
markdown $ ("$$" ++) $ (++ "$$") $ intercalate " \\quad " [
|
||||
"(AB) = " ++ texifyMatrix psl25_gen_AB,
|
||||
"(AB)^3 = " ++ texifyMatrix ((`mod` 5) <$> (psl25_gen_AB^3))
|
||||
]
|
||||
```
|
||||
|
||||
We now have a correspondence between three elements of *A*~5~ and PSL(2, 5).
|
||||
We can "run" both sets of the generators until we associate all elements to one another.
|
||||
This is most visually appealing to see as a Cayley graph:
|
||||
|
||||

|
||||
[
|
||||
![
|
||||
Cayley graph showing an isomorphism between A5 and PSL(2, 5). <br>
|
||||
Order-2 elements are red, order-3 elements are green, and order-5 elements are blue.
|
||||
Purple arrows are order-5 generators, orange arrows are order-2 generators[^4].
|
||||
](./a5_psl25_cayley.png){.narrow}
|
||||
](./a5_psl24_cayley.png)
|
||||
|
||||
[^4]: Different generators appear to be used for *A* and *B* in the above image
|
||||
due to some self-imposed turbulence when writing the original post.
|
||||
Under projective equality, both are the same as our choices of *A* and *B*.
|
||||
|
||||
|
||||
PSL(2, 4)
|
||||
@ -737,7 +736,7 @@ $$
|
||||
|
||||
Scalar multiplication by *α* multiplies the determinant by *α*^2^;
|
||||
by *α*^2^ multiplies the determinant by *α*^4^ = *α*.
|
||||
Thus, SL(2, 4) is also PSL(2, 4), since no scalar multiple has determinant 1.
|
||||
Thus, SL(2, 4) is also PSL(2, 4), since a scalar multiple has determinant 1.
|
||||
|
||||
Let's start by looking at an order-5 matrix over PSL(2, 4).
|
||||
We'll call this matrix *B*' to correspond with our order-5 generator in PSL(2, 5).
|
||||
@ -777,8 +776,8 @@ $$
|
||||
We need to be able to do three things over GL(2, 4) on a computer:
|
||||
|
||||
- multiply matrices over GF(4),
|
||||
- compare those matrices,
|
||||
- compute their determinant, and
|
||||
- compute their determinant,
|
||||
- visually distinguish between each of them, and
|
||||
- be able to systematically write down all of them
|
||||
|
||||
It would then follow for us to repeat what we did with with SL(2, 5).
|
||||
@ -826,7 +825,7 @@ $$
|
||||
f(1) & f(1) \\
|
||||
f(\alpha) & f(\alpha^2)
|
||||
\end{matrix} \right) =
|
||||
f^*((\bar B')^2)
|
||||
f^*((B')^2)
|
||||
\end{align*}
|
||||
\end{gather*}
|
||||
$$
|
||||
@ -877,14 +876,11 @@ All we need to do is find all possible 4-tuples of **0**, *I*, *C*~*p*~, and *C*
|
||||
then arrange each into a 2x2 matrix.
|
||||
Multiplication follows from the typical definition and the multiplicative identity is just *f*\*(*I*).
|
||||
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
--| code-summary: "Haskell implementation of PSL(2, 4)"
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Haskell implementation of PSL(2, 4)
|
||||
</summary>
|
||||
|
||||
```{.haskell}
|
||||
import Data.List (findIndex)
|
||||
import Data.List (elemIndex)
|
||||
|
||||
-- Matrices which obey the same relations as the elements of GF(4)
|
||||
zero_f4 = zero 2
|
||||
@ -896,7 +892,7 @@ alpha2_f4 = toMatrix [[1,1],[1,0]]
|
||||
field4 = [zero_f4, one_f4, alpha_f4, alpha2_f4]
|
||||
|
||||
-- Convenient show function for these matrices
|
||||
showF4 x = case findIndex (==x) field4 of
|
||||
showF4 x = case elemIndex x field4 of
|
||||
Just 0 -> "0"
|
||||
Just 1 -> "1"
|
||||
Just 2 -> "α"
|
||||
@ -909,101 +905,59 @@ psl_24_identity = toMatrix [[one_f4, zero_f4], [zero_f4, one_f4]]
|
||||
-- All possible matrices over GF(4)
|
||||
-- Create a list of 4-lists of elements from GF(4), then
|
||||
-- Shape them into 2x2 matrices
|
||||
f4_matrices = map (toMatrix . reshape 2) $ sequence $ replicate 4 field4
|
||||
f4_matrices = map (toMatrix . reshape 2) $ replicateM 4 field4
|
||||
|
||||
-- Sieve out those which have a determinant of 1 in the field
|
||||
mPSL24 = filter ((==one_f4) . (fmap (`mod` 2)) . laplaceDet) $ f4_matrices
|
||||
mPSL24 = filter ((==one_f4) . fmap (`mod` 2) . laplaceDet) f4_matrices
|
||||
```
|
||||
</details>
|
||||
|
||||
Now that we can generate the group, we can finally repeat what we did with PSL(2, 5).
|
||||
All we have to do is filter out order-2 elements, then further filter
|
||||
for those which have an order-3 product with *B*'.
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Haskell implementation using *B*' as a generator to find candidates for *A*'
|
||||
</summary>
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
--| code-summary: "Haskell implementation using *B*' as a generator to find candidates for *A*'"
|
||||
|
||||
```{.haskell}
|
||||
-- Order with respect to PSL(2, 4): using matrix multiplication (mod 2)
|
||||
-- and projective equality to the identity matrix
|
||||
orderPSL24 = orderWith (\x -> fmap (fmap (`mod` 2)) . (x*))) (== psl_24_identity)
|
||||
orderPSL24 = orderWith (\x -> fmap (fmap (`mod` 2)) . (x*)) (== psl_24_identity)
|
||||
|
||||
-- Only order 2 elements of PSL(2, 4)
|
||||
psl24_order2 = filter ((==2) . orderPSL24) $ mPSL24
|
||||
psl24_order2 = filter ((==2) . orderPSL24) mPSL24
|
||||
|
||||
-- Start with B as a generator
|
||||
psl24_gen_B = toMatrix [[zero_f4, alpha_f4], [alpha2_f4, alpha2_f4]]
|
||||
|
||||
-- Find an order 2 element whose product with `psl24_gen_B` has order 3
|
||||
psl24_gen_A_candidates = filter ((==3) . orderPSL24 . (psl24_gen_B*))
|
||||
psl24_gen_A_candidates = filter ((==3) . orderPSL24 . (psl24_gen_B |*|))
|
||||
psl24_order2
|
||||
|
||||
-- Candidate matrices:
|
||||
--
|
||||
-- ["0","1"]
|
||||
-- ["1","0"]
|
||||
--
|
||||
-- ["0","α^2"]
|
||||
-- ["α","0"]
|
||||
--
|
||||
-- ["1","0"]
|
||||
-- ["1","1"]
|
||||
--
|
||||
-- ["1","α^2"]
|
||||
-- ["0","1"]
|
||||
--
|
||||
-- ["α","1"]
|
||||
-- ["α","α"]
|
||||
markdown $ ("$$ A' = " ++) $ (++ "$$") $ intercalate " ~,~ " $
|
||||
map (texifyMatrix' showF4) psl24_gen_A_candidates
|
||||
```
|
||||
</details>
|
||||
|
||||
Finally, we can decide on an *A*', the order-2 generator with the properties we wanted.
|
||||
We'll pick the second entry as our choice of *A*'.
|
||||
We note that the product *A'B'*, does indeed have order 3.
|
||||
|
||||
$$
|
||||
\begin{array}{}
|
||||
\begin{gather*}
|
||||
A' = \left(\begin{matrix}
|
||||
0 & \alpha^2 \\
|
||||
\alpha & 0
|
||||
\end{matrix} \right)
|
||||
\qquad
|
||||
(A')^2 = \left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 1
|
||||
\end{matrix}\right)
|
||||
\end{gather*}
|
||||
\\ \\ \hline \\
|
||||
\begin{gather*}
|
||||
A'B' =
|
||||
\left(\begin{matrix}
|
||||
\alpha & \alpha \\
|
||||
0 & \alpha^2
|
||||
\end{matrix} \right)
|
||||
\qquad
|
||||
(A'B')^2 =
|
||||
\left(\begin{matrix}
|
||||
\alpha^2 & \alpha \\
|
||||
0 & \alpha
|
||||
\end{matrix} \right)
|
||||
\qquad
|
||||
(A'B')^3 =
|
||||
\left(\begin{matrix}
|
||||
1 & 0 \\
|
||||
0 & 1
|
||||
\end{matrix} \right)
|
||||
\qquad
|
||||
\end{gather*}
|
||||
\end{array}
|
||||
$$
|
||||
```{haskell}
|
||||
--| code-fold: true
|
||||
|
||||
Then, we can arrange them on a Cayley graph in the same way as PSL(2, 5):
|
||||
psl24_gen_AB = fmap (`mod` 2) <$> (psl24_gen_A_candidates !! 1) |*| psl24_gen_B
|
||||
|
||||
markdown $ ("$$" ++) $ (++ "$$") $ intercalate " \\quad " [
|
||||
"(A'B') = " ++ texifyMatrix' showF4 psl24_gen_AB,
|
||||
"(A'B')^3 = " ++ texifyMatrix' showF4 (fmap (`mod` 2) <$> (psl24_gen_AB^3))
|
||||
]
|
||||
```
|
||||
|
||||
{.narrow}
|
||||
](./a5_psl24_cayley.png)
|
||||
|
||||
|
||||
@ -1011,16 +965,20 @@ Closing
|
||||
-------
|
||||
|
||||
This post addresses my original goal in implementing finite fields,
|
||||
namely computationally finding an explicit map between *A*^5^ and PSL(2, 4).
|
||||
namely computationally finding an explicit map between *A*~5~ and PSL(2, 4).
|
||||
I believe the results are a little more satisfying than attempting to wrap your head
|
||||
around group-theoretic proofs.
|
||||
That's not to discount the power and astounding amount of work that goes into the latter method.
|
||||
That's not to discount the power and incredible logic that goes into the latter method.
|
||||
It does tend to leave things rather opaque, however.
|
||||
|
||||
If you'd prefer a more interactive diagram showing the above isomorphisms,
|
||||
I've gone to the liberty of creating a hoverable SVG:
|
||||
|
||||

|
||||
[
|
||||
{.narrow}
|
||||
](./a5_psl24_psl25_isomorphism.svg)
|
||||
|
||||
This post slightly diverts our course from the previous one's focus on fields.
|
||||
The [next one](../4) will focus on more results regarding the treatment of layered matrices.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user