moonlight-linalg-0.1.0.0: test/dense/FieldSpec.hs
module FieldSpec
( tests,
)
where
import Moonlight.Core (canInvert)
import Moonlight.LinAlg
( fromListMatrix,
gf2One,
gf2Zero,
kernel,
kernelBasisVectors,
mult,
pluDecompFullRank,
pluLower,
pluPermutation,
pluUpper,
rank,
toListMatrix,
toListVector,
)
import Helpers (extractRight)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit
( Assertion,
assertBool,
assertEqual,
testCase,
)
tests :: TestTree
tests =
testGroup
"Field"
[ testCase "pluDecompFullRank reconstructs matrix for non-singular input" testPluReconstruction,
testCase "pluDecompFullRank captures row permutations for zero-leading pivots" testPluPivoting,
testCase "rank over GF2 returns expected value" testRank,
testCase "kernel over GF2 returns basis vectors" testKernel,
testCase "GF2 rank skips all-zero column (zero is not invertible)" testGF2ZeroColumnRank,
testCase "GF2 canInvert rejects zero" testGF2CanInvertZero
]
testPluReconstruction :: Assertion
testPluReconstruction =
let result = do
matrixValue <- fromListMatrix @2 @2 @Double [4.0, 3.0, 6.0, 3.0]
pluValue <- pluDecompFullRank matrixValue
let permutation = pluPermutation pluValue
lower = pluLower pluValue
upper = pluUpper pluValue
lhs <- mult permutation matrixValue
reconstructed <- mult lower upper
pure (toListMatrix lhs, toListMatrix reconstructed)
in extractRight result (\(lhsValues, rhsValues) -> assertEqual "PLU reconstruction" lhsValues rhsValues)
testPluPivoting :: Assertion
testPluPivoting =
let result = do
matrixValue <- fromListMatrix @2 @2 @Double [0.0, 1.0, 1.0, 1.0]
pluValue <- pluDecompFullRank matrixValue
let permutation = pluPermutation pluValue
lower = pluLower pluValue
upper = pluUpper pluValue
lhs <- mult permutation matrixValue
rhs <- mult lower upper
pure (toListMatrix lhs, toListMatrix rhs)
in extractRight result (\(lhsValues, rhsValues) -> assertEqual "PLU reconstruction with permutation" lhsValues rhsValues)
testRank :: Assertion
testRank =
let result = do
matrixValue <- fromListMatrix @2 @2 [gf2One, gf2One, gf2One, gf2One]
rank matrixValue
in extractRight result (\value -> assertEqual "GF2 rank" 1 value)
testKernel :: Assertion
testKernel =
let result = do
matrixValue <- fromListMatrix @2 @2 [gf2One, gf2One, gf2One, gf2One]
fmap kernelBasisVectors (kernel matrixValue)
in extractRight result (\basis -> assertEqual "GF2 kernel basis" [[gf2One, gf2One]] (map toListVector basis))
testGF2ZeroColumnRank :: Assertion
testGF2ZeroColumnRank =
let result = do
matrixValue <- fromListMatrix @2 @3 [gf2Zero, gf2One, gf2Zero, gf2Zero, gf2Zero, gf2One]
rank matrixValue
in extractRight result (\value -> assertEqual "rank of matrix with all-zero first column" 2 value)
testGF2CanInvertZero :: Assertion
testGF2CanInvertZero = do
assertBool "GF2Zero must not be invertible" (not (canInvert gf2Zero))
assertBool "GF2One must be invertible" (canInvert gf2One)