packages feed

toysolver-0.8.0: test/Test/CNF.hs

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Test.CNF (cnfTestGroup) where

import Data.ByteString.Builder
import qualified Data.ByteString.Lazy.Char8 as BL
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import Test.Tasty.TH
import ToySolver.FileFormat
import qualified ToySolver.FileFormat.CNF as CNF

import Test.SAT.Utils

------------------------------------------------------------------------

prop_CNF_ReadWrite_Invariance :: Property
prop_CNF_ReadWrite_Invariance = forAll arbitraryCNF $ \cnf ->
  CNF.parse (toLazyByteString (CNF.render cnf)) == Right cnf

prop_GCNF_ReadWrite_Invariance :: Property
prop_GCNF_ReadWrite_Invariance = forAll arbitraryGCNF $ \gcnf ->
  CNF.parse (toLazyByteString (CNF.render gcnf)) == Right gcnf

prop_WCNF_ReadWrite_Invariance :: Property
prop_WCNF_ReadWrite_Invariance = forAll arbitraryWCNF $ \wcnf ->
  CNF.parse (toLazyByteString (CNF.render wcnf)) == Right wcnf

prop_NewWCNF_ReadWrite_Invariance :: Property
prop_NewWCNF_ReadWrite_Invariance = forAll arbitraryNewWCNF $ \wcnf ->
  CNF.parse (toLazyByteString (CNF.render wcnf)) == Right wcnf

prop_QDimacs_ReadWrite_Invariance :: Property
prop_QDimacs_ReadWrite_Invariance = forAll arbitraryQDimacs $ \qdimacs ->
  CNF.parse (toLazyByteString (CNF.render qdimacs)) == Right qdimacs

prop_GCNF_from_CNF :: Property
prop_GCNF_from_CNF = forAll arbitraryCNF $ \cnf ->
  case CNF.parse (toLazyByteString (CNF.render cnf)) of
    Left _ -> False
    Right gcnf -> and
      [ CNF.gcnfNumVars gcnf == CNF.cnfNumVars cnf
      , CNF.gcnfNumClauses gcnf == CNF.cnfNumClauses cnf
      , CNF.gcnfLastGroupIndex gcnf == CNF.cnfNumClauses cnf
      , CNF.gcnfClauses gcnf == zip [1..] (CNF.cnfClauses cnf)
      ]

prop_WCNF_from_CNF :: Property
prop_WCNF_from_CNF = forAll arbitraryCNF $ \cnf ->
  case CNF.parse (toLazyByteString (CNF.render cnf)) of
    Left _ -> False
    Right wcnf -> and
      [ CNF.wcnfNumVars wcnf == CNF.cnfNumVars cnf
      , CNF.wcnfNumClauses wcnf == CNF.cnfNumClauses cnf
      , CNF.wcnfTopCost wcnf > fromIntegral (CNF.cnfNumClauses cnf)
      , CNF.wcnfClauses wcnf == map (\c -> (1,c)) (CNF.cnfClauses cnf)
      ]

prop_QDimacs_from_CNF :: Property
prop_QDimacs_from_CNF = forAll arbitraryCNF $ \cnf ->
  case CNF.parse (toLazyByteString (CNF.render cnf)) of
    Left _ -> False
    Right qdimacs -> and
      [ CNF.qdimacsNumVars qdimacs == CNF.cnfNumVars cnf
      , CNF.qdimacsNumClauses qdimacs == CNF.cnfNumClauses cnf
      , CNF.qdimacsPrefix qdimacs == []
      , CNF.qdimacsMatrix qdimacs == CNF.cnfClauses cnf
      ]

-- example from https://maxsat-evaluations.github.io/2021/format.html
case_parse_new_WCNF_as_old :: IO ()
case_parse_new_WCNF_as_old = parse s @?= Right expected
  where
    s = BL.pack $ unlines
        [ "c This is a comment"
        , "c Example 1...another comment"
        , "h 1 2 3 4 0"
        , "1 -3 -5 6 7 0"
        , "6 -1 -2 0"
        , "4 1 6 -7 0"
        ]
    h = 12
    expected =
      CNF.WCNF
      { CNF.wcnfNumVars = 7
      , CNF.wcnfNumClauses = 4
      , CNF.wcnfTopCost = h
      , CNF.wcnfClauses =
          [ (h, CNF.packClause [1,2,3,4])
          , (1, CNF.packClause [-3,-5,6,7])
          , (6, CNF.packClause [-1,-2])
          , (4, CNF.packClause [1,6,-7])
          ]
      }

-- example from https://maxsat-evaluations.github.io/2021/format.html
case_parse_old_WCNF_as_new :: IO ()
case_parse_old_WCNF_as_new = parse s @?= Right expected
  where
    s = BL.pack $ unlines
        [ "c This is a comment"
        , "c Example 1...another comment"
        , "p wcnf 7 4 12 "
        , "12 1 2 3 4 0"
        , "1 -3 -5 6 7 0"
        , "6 -1 -2 0"
        , "4 1 6 -7 0"
        ]
    expected =
      CNF.NewWCNF
        [ (Nothing, CNF.packClause [1,2,3,4])
        , (Just 1, CNF.packClause [-3,-5,6,7])
        , (Just 6, CNF.packClause [-1,-2])
        , (Just 4, CNF.packClause [1,6,-7])
        ]

------------------------------------------------------------------------
-- Test harness

cnfTestGroup :: TestTree
cnfTestGroup = $(testGroupGenerator)