assertica / test /Test /StdLib /Monomorphism.hs
SNAPKITTYWEST's picture
October 2026 main drop: mirror from GitHub
a10b189 verified
Raw History Blame Contribute Delete
17 kB
{-# LANGUAGE OverloadedStrings #-}
{-|
Module : Test.StdLib.Monomorphism
Description : Tests for lattice monomorphism theorem
Copyright : (c) 2026 Ahmad Ali Parr
-}
module Test.StdLib.Monomorphism
( tests
) where
import Test.Tasty
import Test.Tasty.HUnit
import Assertica.Core.AST
import Assertica.Core.ProofTerm
import Assertica.StdLib.Lattice
import Assertica.StdLib.Monomorphism
-- ============================================================================
-- UNIT TESTS: MONOMORPHISM THEOREM
-- ============================================================================
tests :: TestTree
tests = testGroup "Assertica.StdLib.Monomorphism"
[ testGroup "Monomorphism Theorem"
[ testCase "Identity homomorphism is monomorphic" testIdentityMonomorphic
, testCase "Same homomorphisms agree on generators" testSameHomsAgree
, testCase "Monomorphism proof is constructible" testMonomorphismConstructible
, testCase "Monomorphism proof on generators" testMonomorphismOnGenerators
, testCase "Monomorphism proof on compounds" testMonomorphismOnCompounds
]
, testGroup "Homomorphism Equality"
[ testCase "Equal homomorphisms have same map" testEqualHomsSameMap
, testCase "Homomorphism equality proof" testHomEqualityProof
]
, testGroup "Structural Induction"
[ testCase "Base case: generators" testInductionBase
, testCase "Induction step: join" testInductionStepJoin
, testCase "Induction step: meet" testInductionStepMeet
, testCase "Full induction" testFullInduction
]
, testGroup "Generator Extension"
[ testCase "Extension on generators" testExtensionGenerators
, testCase "Extended function preserves joins" testExtensionPreservesJoins
, testCase "Extended function preserves meets" testExtensionPreservesMeets
, testCase "Unique extension" testUniqueExtension
]
, testGroup "Homomorphism Composition"
[ testCase "Composed homomorphisms" testComposedHomomorphisms
, testCase "Composition preserves monomorphism" testCompositionMonomorphism
]
, testGroup "Proof Term Correctness"
[ testCase "Monomorphism proof type-checks" testMonomorphismProofChecks
, testCase "Induction step proofs" testInductionStepProofs
, testCase "Extension proofs" testExtensionProofs
]
, testGroup "Determinism"
[ testCase "Monomorphism proof is deterministic" testMonomorphismDeterminism
, testCase "Structural induction is deterministic" testInductionDeterminism
, testCase "Extension is deterministic" testExtensionDeterminism
]
, testGroup "Negative Tests"
[ testCase "Different homomorphisms may not agree" testDifferentHomsMayDiffer
, testCase "Non-agreeing on generators" testNonAgreeingGenerators
]
]
-- ============================================================================
-- MONOMORPHISM THEOREM TESTS
-- ============================================================================
testIdentityMonomorphic :: Assertion
testIdentityMonomorphic =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl -- Identity agrees with itself
a = Const (BoolLit True)
proof = monomorphismTheorem booleanLattice booleanLattice f g genEq a
in proof `shouldBeProofTerm` ()
testSameHomsAgree :: Assertion
testSameHomsAgree =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
-- Same homomorphism always agrees
in homMap f (Const (BoolLit True)) @?= homMap g (Const (BoolLit True))
testMonomorphismConstructible :: Assertion
testMonomorphismConstructible =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
a = Const (BoolLit True)
proof = monomorphismTheorem booleanLattice booleanLattice f g genEq a
in case proof of
_ -> assertBool "Monomorphism proof is constructible" True
testMonomorphismOnGenerators :: Assertion
testMonomorphismOnGenerators =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
-- Both agree on generators
genEq gen = Refl
-- Generator (a constant)
gen = Const (BoolLit True)
proof = monomorphismTheorem booleanLattice booleanLattice f g genEq gen
in proof @?= Refl
testMonomorphismOnCompounds :: Assertion
testMonomorphismOnCompounds =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
-- Compound: a ⊔ b
compound = Constr (QName [] "join") [Const (BoolLit True), Const (BoolLit False)]
proof = monomorphismTheorem booleanLattice booleanLattice f g genEq compound
in proof `shouldBeProofTerm` ()
-- ============================================================================
-- HOMOMORPHISM EQUALITY TESTS
-- ============================================================================
testEqualHomsSameMap :: Assertion
testEqualHomsSameMap =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
a = Const (BoolLit True)
in homMap f a @?= homMap g a
testHomEqualityProof :: Assertion
testHomEqualityProof =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
proof = homomorphismsEqual booleanLattice booleanLattice f g genEq
in proof `shouldBeProofTerm` ()
-- ============================================================================
-- STRUCTURAL INDUCTION TESTS
-- ============================================================================
testInductionBase :: Assertion
testInductionBase =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
genProof gen = Refl
gen = Const (BoolLit True)
proof = inductionBase booleanLattice genProof gen
in proof @?= Refl
testInductionStepJoin :: Assertion
testInductionStepJoin =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
a = Const (BoolLit True)
b = Const (BoolLit False)
hypA = Refl
hypB = Refl
proof = inductionStep booleanLattice booleanLattice f g a b hypA hypB
in proof `shouldBeProofTerm` ()
testInductionStepMeet :: Assertion
testInductionStepMeet =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
a = Const (BoolLit True)
b = Const (BoolLit False)
hypA = Refl
hypB = Refl
proof = inductionStep booleanLattice booleanLattice f g a b hypA hypB
in proof `shouldBeProofTerm` ()
testFullInduction :: Assertion
testFullInduction =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
-- Complex term: (a ⊔ b) ⊓ (c ⊔ d)
a = Const (BoolLit True)
b = Const (BoolLit False)
c = Const (BoolLit True)
d = Const (BoolLit False)
complex = Constr (QName [] "meet")
[ Constr (QName [] "join") [a, b]
, Constr (QName [] "join") [c, d]
]
proof = structuralInductionLattice booleanLattice booleanLattice f g genEq complex
in proof `shouldBeProofTerm` ()
-- ============================================================================
-- GENERATOR EXTENSION TESTS
-- ============================================================================
testExtensionGenerators :: Assertion
testExtensionGenerators =
let phi gen = Const (IntLit 1) -- Map everything to 1
hom = generatorExtension booleanLattice phi
gen = Const (BoolLit True)
in homMap hom gen @?= Const (IntLit 1)
testExtensionPreservesJoins :: Assertion
testExtensionPreservesJoins =
let phi gen = Const (IntLit 1)
hom = generatorExtension booleanLattice phi
a = Const (BoolLit True)
b = Const (BoolLit False)
proof = homPreservesJoin hom a b
in proof @?= Refl
testExtensionPreservesMeets :: Assertion
testExtensionPreservesMeets =
let phi gen = Const (IntLit 1)
hom = generatorExtension booleanLattice phi
a = Const (BoolLit True)
b = Const (BoolLit False)
proof = homPreservesMeet hom a b
in proof @?= Refl
testUniqueExtension :: Assertion
testUniqueExtension =
let phi gen = Const (IntLit 1)
a = Const (BoolLit True)
proof = uniqueExtension booleanLattice booleanLattice phi a
in proof `shouldBeProofTerm` ()
-- ============================================================================
-- HOMOMORPHISM COMPOSITION TESTS
-- ============================================================================
testComposedHomomorphisms :: Assertion
testComposedHomomorphisms =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
a = Const (BoolLit True)
composed = homMap f (homMap g a)
in composed @?= a
testCompositionMonomorphism :: Assertion
testCompositionMonomorphism =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
a = Const (BoolLit True)
proof = monomorphismTheorem booleanLattice booleanLattice f g genEq a
in proof `shouldBeProofTerm` ()
-- ============================================================================
-- PROOF TERM CORRECTNESS TESTS
-- ============================================================================
testMonomorphismProofChecks :: Assertion
testMonomorphismProofChecks =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
a = Const (BoolLit True)
proof = monomorphismTheorem booleanLattice booleanLattice f g genEq a
in case proof of
_ -> assertBool "Monomorphism proof exists" True
testInductionStepProofs :: Assertion
testInductionStepProofs =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
a = Const (BoolLit True)
b = Const (BoolLit False)
proof = inductionStep booleanLattice booleanLattice f g a b Refl Refl
in case proof of
_ -> assertBool "Induction step proof exists" True
testExtensionProofs :: Assertion
testExtensionProofs =
let phi gen = Const (IntLit 1)
ext = extendFromGenerators booleanLattice booleanLattice phi
a = Const (BoolLit True)
in homMap ext a @?= phi a
-- ============================================================================
-- DETERMINISM TESTS
-- ============================================================================
testMonomorphismDeterminism :: Assertion
testMonomorphismDeterminism =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
a = Const (BoolLit True)
proof1 = monomorphismTheorem booleanLattice booleanLattice f g genEq a
proof2 = monomorphismTheorem booleanLattice booleanLattice f g genEq a
in proof1 @?= proof2
testInductionDeterminism :: Assertion
testInductionDeterminism =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = f
genEq gen = Refl
a = Const (BoolLit True)
proof1 = structuralInductionLattice booleanLattice booleanLattice f g genEq a
proof2 = structuralInductionLattice booleanLattice booleanLattice f g genEq a
in proof1 @?= proof2
testExtensionDeterminism :: Assertion
testExtensionDeterminism =
let phi gen = Const (IntLit 1)
ext1 = extendFromGenerators booleanLattice booleanLattice phi
ext2 = extendFromGenerators booleanLattice booleanLattice phi
a = Const (BoolLit True)
in homMap ext1 a @?= homMap ext2 a
-- ============================================================================
-- NEGATIVE TESTS
-- ============================================================================
testDifferentHomsMayDiffer :: Assertion
testDifferentHomsMayDiffer =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = \_ -> Const (BoolLit False) -- Constant False
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
a = Const (BoolLit True)
in homMap f a /= homMap g a @? "Different homomorphisms may map differently"
testNonAgreeingGenerators :: Assertion
testNonAgreeingGenerators =
let f = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = id
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
g = LatticeHomomorphism
{ homSource = booleanLattice
, homTarget = booleanLattice
, homMap = \_ -> Const (BoolLit False)
, homPreservesJoin = \_ _ -> Refl
, homPreservesMeet = \_ _ -> Refl
}
true = Const (BoolLit True)
in homMap f true /= homMap g true @? "Homomorphisms that differ on generators are different"
-- ============================================================================
-- HELPER FUNCTIONS
-- ============================================================================
shouldBeProofTerm :: Proof -> () -> Assertion
shouldBeProofTerm proof () = case proof of
Refl {} -> assertBool "Is a proof term (Refl)" True
Symm {} -> assertBool "Is a proof term (Symm)" True
Trans {} -> assertBool "Is a proof term (Trans)" True
Intro {} -> assertBool "Is a proof term (Intro)" True
Elim {} -> assertBool "Is a proof term (Elim)" True
Constr' {} -> assertBool "Is a proof term (Constr')" True
Opaque {} -> assertBool "Is a proof term (Opaque)" True
ProofAnn {} -> assertBool "Is a proof term (ProofAnn)" True
_ -> assertFailure "Not a proper proof term"