Cluster.hs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. {-# LANGUAGE TemplateHaskell #-}
  2. module Internal.Utils.Cluster ( tests ) where
  3. import Agda.Utils.Cluster
  4. import Data.Char
  5. import Data.List (delete, intersect, sort)
  6. import Data.List.NonEmpty (NonEmpty(..))
  7. import qualified Data.List.NonEmpty as NonEmpty
  8. import qualified Data.Foldable as Fold
  9. import Internal.Helpers
  10. import Internal.Utils.NonEmptyList () -- instances only
  11. ------------------------------------------------------------------------
  12. -- * Properties
  13. ------------------------------------------------------------------------
  14. -- | A type used for the tests.
  15. type C = Int
  16. -- Fundamental properties: soundness and completeness
  17. -- | Not too many clusters. (Algorithm equated all it could.)
  18. --
  19. -- Each element in a cluster shares a characteristic with at least one
  20. -- other element in the same cluster.
  21. prop_cluster_complete :: Fun Int (NonEmpty C) -> [Int] -> Bool
  22. prop_cluster_complete (Fun _ f) as =
  23. (`all` cluster f as) $ \ cl ->
  24. (`all` cl) $ \ a ->
  25. let csa = NonEmpty.toList $ f a in
  26. let cl' = delete a $ NonEmpty.toList cl in
  27. -- Either a is the single element of the cluster, or it shares a characteristic c
  28. -- with some other element b of the same cluster.
  29. null cl' || not (null [ (b,c) | b <- cl', c <- NonEmpty.toList (f b), c `elem` csa ])
  30. -- | Not too few clusters. (Algorithm did not equate too much.)
  31. --
  32. -- Elements of different clusters share no characteristics.
  33. prop_cluster_sound :: Fun Int (NonEmpty C) -> [Int] -> Bool
  34. prop_cluster_sound (Fun _ f) as =
  35. (`all` [ (c, d) | let cs = cluster f as, c <- cs, d <- cs, c /= d]) $ \ (c, d) ->
  36. (`all` c) $ \ a ->
  37. (`all` d) $ \ b ->
  38. null $ (NonEmpty.toList $ f a) `intersect` (NonEmpty.toList $ f b)
  39. isSingleton, exactlyTwo, atLeastTwo :: Foldable t => t a -> Bool
  40. isSingleton x = Fold.length x == 1
  41. exactlyTwo x = Fold.length x == 2
  42. atLeastTwo x = Fold.length x >= 2
  43. prop_cluster_empty :: Bool
  44. prop_cluster_empty =
  45. null (cluster (const (0 :| [])) [])
  46. prop_cluster_permutation :: Fun Int (NonEmpty C) -> [Int] -> Bool
  47. prop_cluster_permutation (Fun _ f) as =
  48. sort as == sort (concatMap NonEmpty.toList (cluster f as))
  49. prop_cluster_single :: a -> [a] -> Bool
  50. prop_cluster_single a as =
  51. isSingleton $ cluster (const (0 :| [])) $ (a:as)
  52. prop_cluster_idem :: Fun a (NonEmpty C) -> a -> [a] -> Bool
  53. prop_cluster_idem (Fun _ f) a as =
  54. isSingleton $ cluster f $ NonEmpty.toList $ head $ cluster f (a:as)
  55. prop_two_clusters :: [Int] -> Bool
  56. prop_two_clusters as =
  57. atLeastTwo $ cluster (\ x -> x :| [x]) (-1:1:as)
  58. -- | An example.
  59. --
  60. -- "anabel" is related to "babel" (common letter 'a' in 2-letter prefix)
  61. -- which is related to "bond" (common letter 'b').
  62. --
  63. -- "hurz", "furz", and "kurz" are all related (common letter 'u').
  64. test :: [NonEmpty String]
  65. test = cluster (\ (x:y:_) -> ord x :| [ord y])
  66. ["anabel","bond","babel","hurz","furz","kurz"]
  67. prop_test :: Bool
  68. prop_test = test ==
  69. [ "anabel" :| "bond" : "babel" : []
  70. , "hurz" :| "furz" : "kurz" : []
  71. ]
  72. -- | Modified example (considering only the first letter).
  73. test1 :: [NonEmpty String]
  74. test1 = cluster (\ (x:_:_) -> ord x :| [])
  75. ["anabel","bond","babel","hurz","furz","kurz"]
  76. prop_test1 :: Bool
  77. prop_test1 = test1 ==
  78. [ "anabel" :| []
  79. , "bond" :| "babel" : []
  80. , "furz" :| []
  81. , "hurz" :| []
  82. , "kurz" :| []
  83. ]
  84. ------------------------------------------------------------------------
  85. -- * All tests
  86. ------------------------------------------------------------------------
  87. -- Template Haskell hack to make the following $allProperties work
  88. -- under ghc-7.8.
  89. return [] -- KEEP!
  90. -- | All tests as collected by 'allProperties'.
  91. --
  92. -- Using 'allProperties' is convenient and superior to the manual
  93. -- enumeration of tests, since the name of the property is added
  94. -- automatically.
  95. tests :: TestTree
  96. tests = testProperties "Internal.Utils.Cluster" $allProperties