| module Main where | |
| import System.Exit (exitSuccess, exitFailure) | |
| import qualified Data.Map.Strict as Map | |
| import IR.Boolean | |
| import IR.NAND | |
| import IR.BitVec | |
| import SAT.CNF | |
| import SAT.UnitProp | |
| import SAT.DPLL | |
| import Proof.Certificate | |
| import Proof.Produce | |
| import Checker.Kernel | |
| import Language.Parser | |
| import Language.Elaborator | |
| main :: IO () | |
| main = do | |
| results <- sequence | |
| [ test "NAND truth table" testNAND | |
| , test "NOT from NAND" testNOT | |
| , test "AND from NAND" testAND | |
| , test "OR from NAND" testOR | |
| , test "XOR from NAND" testXOR | |
| , test "Half adder sum" testHalfAdderSum | |
| , test "Half adder carry" testHalfAdderCarry | |
| , test "BitVec add 3+5=8" testBitVecAdd | |
| , test "Tseitin preserves satisfiability" testTseitin | |
| , test "DPLL finds SAT" testDPLLSat | |
| , test "DPLL finds UNSAT" testDPLLUnsat | |
| , test "Unit propagation" testUnitProp | |
| , test "Proof certificate valid" testProofValid | |
| , test "Checker accepts valid" testCheckerAccepts | |
| , test "Checker rejects invalid" testCheckerRejects | |
| , test "Parse module" testParse | |
| , test "Elaborate module" testElaborate | |
| , test "NAND normal form" testNANDNormal | |
| , test "De Morgan via eval" testDeMorgan | |
| , test "MUX correctness" testMux | |
| ] | |
| let passed = length (filter id results) | |
| total = length results | |
| putStrLn $ "\n" ++ show passed ++ "/" ++ show total ++ " tests passed." | |
| if passed == total then exitSuccess else exitFailure | |
| test :: String -> Bool -> IO Bool | |
| test name result = do | |
| putStrLn $ (if result then "[OK] " else "[FAIL]") ++ " " ++ name | |
| return result | |
| testNAND :: Bool | |
| testNAND = | |
| eval Map.empty (BNand BTrue BTrue) == False && | |
| eval Map.empty (BNand BTrue BFalse) == True && | |
| eval Map.empty (BNand BFalse BTrue) == True && | |
| eval Map.empty (BNand BFalse BFalse) == True | |
| testNOT :: Bool | |
| testNOT = | |
| eval Map.empty (bnot BTrue) == False && | |
| eval Map.empty (bnot BFalse) == True | |
| testAND :: Bool | |
| testAND = | |
| eval Map.empty (band BTrue BTrue) == True && | |
| eval Map.empty (band BTrue BFalse) == False && | |
| eval Map.empty (band BFalse BTrue) == False && | |
| eval Map.empty (band BFalse BFalse) == False | |
| testOR :: Bool | |
| testOR = | |
| eval Map.empty (bor BTrue BTrue) == True && | |
| eval Map.empty (bor BTrue BFalse) == True && | |
| eval Map.empty (bor BFalse BTrue) == True && | |
| eval Map.empty (bor BFalse BFalse) == False | |
| testXOR :: Bool | |
| testXOR = | |
| eval Map.empty (bxor BTrue BTrue) == False && | |
| eval Map.empty (bxor BTrue BFalse) == True && | |
| eval Map.empty (bxor BFalse BTrue) == True && | |
| eval Map.empty (bxor BFalse BFalse) == False | |
| testHalfAdderSum :: Bool | |
| testHalfAdderSum = | |
| let (s, _) = halfAdder BFalse BFalse in eval Map.empty s == False && | |
| let (s, _) = halfAdder BTrue BFalse in eval Map.empty s == True && | |
| let (s, _) = halfAdder BFalse BTrue in eval Map.empty s == True && | |
| let (s, _) = halfAdder BTrue BTrue in eval Map.empty s == False | |
| testHalfAdderCarry :: Bool | |
| testHalfAdderCarry = | |
| let (_, c) = halfAdder BFalse BFalse in eval Map.empty c == False && | |
| let (_, c) = halfAdder BTrue BFalse in eval Map.empty c == False && | |
| let (_, c) = halfAdder BFalse BTrue in eval Map.empty c == False && | |
| let (_, c) = halfAdder BTrue BTrue in eval Map.empty c == True | |
| testBitVecAdd :: Bool | |
| testBitVecAdd = | |
| let a = bvConst 4 3 | |
| b = bvConst 4 5 | |
| result = bvAdd a b | |
| check = bvEq result (bvConst 4 8) | |
| in eval Map.empty check == True | |
| testTseitin :: Bool | |
| testTseitin = | |
| let expr = band (BVar 1) (BVar 2) | |
| cnf = tseitin expr | |
| in cnfNumVars cnf > 0 && not (null (cnfClauses cnf)) | |
| testDPLLSat :: Bool | |
| testDPLLSat = | |
| let cnf = CNF [[Pos 1, Pos 2], [Neg 1, Pos 2]] 2 | |
| in case dpll cnf of | |
| SAT _ -> True | |
| UNSAT -> False | |
| testDPLLUnsat :: Bool | |
| testDPLLUnsat = | |
| let cnf = CNF [[Pos 1], [Neg 1]] 1 | |
| in case dpll cnf of | |
| UNSAT -> True | |
| SAT _ -> False | |
| testUnitProp :: Bool | |
| testUnitProp = | |
| let clauses = [[Pos 1], [Neg 1, Pos 2]] | |
| in case unitPropagate Map.empty clauses of | |
| Propagated asgn _ -> Map.lookup 1 asgn == Just True | |
| Conflict -> False | |
| testProofValid :: Bool | |
| testProofValid = | |
| let cert = proveValidity "test_true" BTrue | |
| in proofConclusion cert == Valid | |
| testCheckerAccepts :: Bool | |
| testCheckerAccepts = | |
| let cert = proveValidity "trivial" BTrue | |
| in case checkCertificate cert of | |
| Verified _ -> True | |
| Rejected _ _ -> False | |
| testCheckerRejects :: Bool | |
| testCheckerRejects = | |
| let cert = (emptyProof "bad" Valid) | |
| { proofSteps = [Resolution [Pos 1] [Pos 2] [Neg 3] 99] } | |
| in case checkCertificate cert of | |
| Rejected _ _ -> True | |
| Verified _ -> False | |
| testParse :: Bool | |
| testParse = | |
| case parseModule "test" "def not(x) = (x | x);\nassert not(true);" of | |
| Right _ -> True | |
| Left _ -> False | |
| testElaborate :: Bool | |
| testElaborate = | |
| case parseModule "test" "def id(x) = x;\nassert id(true);" of | |
| Right m -> case elaborate m of | |
| Right _ -> True | |
| Left _ -> False | |
| Left _ -> False | |
| testNANDNormal :: Bool | |
| testNANDNormal = | |
| isNANDNormal (BNand (BVar 1) (BVar 2)) && | |
| not (isNANDNormal BTrue) && | |
| not (isNANDNormal BFalse) | |
| testDeMorgan :: Bool | |
| testDeMorgan = | |
| let env tt = Map.fromList [(1, fst tt), (2, snd tt)] | |
| cases = [(True, True), (True, False), (False, True), (False, False)] | |
| lhs e = bnot (band (BVar 1) (BVar 2)) | |
| rhs e = bor (bnot (BVar 1)) (bnot (BVar 2)) | |
| in all (\c -> eval (env c) (lhs c) == eval (env c) (rhs c)) cases | |
| testMux :: Bool | |
| testMux = | |
| let mux sel a b = bor (band (bnot sel) a) (band sel b) | |
| cases = [ (False, False, False, False) | |
| , (False, False, True, False) | |
| , (False, True, False, True) | |
| , (False, True, True, True) | |
| , (True, False, False, False) | |
| , (True, False, True, True) | |
| , (True, True, False, False) | |
| , (True, True, True, True) | |
| ] | |
| check (s, a, b, expected) = | |
| let se = if s then BTrue else BFalse | |
| ae = if a then BTrue else BFalse | |
| be = if b then BTrue else BFalse | |
| in eval Map.empty (mux se ae be) == expected | |
| in all check cases | |