dtw-0.9.2.0: test/MainTest.hs
{-# LANGUAGE ViewPatterns #-}
module Main where
-- module under test
import Data.DTW
import Test.Framework
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck
import Data.Sequence (Seq(..), ViewL(..), (<|))
import qualified Data.Sequence as S
import Data.Functor
newtype SmallNonEmptySeq a = SmallNonEmptySeq { getSmallNonEmpty :: [a] }
deriving (Show, Eq)
instance Arbitrary a => Arbitrary (SmallNonEmptySeq a) where
arbitrary = SmallNonEmptySeq <$> listOf arbitrary `suchThat` (\l -> length l > 2 && length l < 10)
newtype MediumNonEmptySeq a = MediumNonEmptySeq { getMediumNonEmpty :: [a] }
deriving (Show, Eq)
instance Arbitrary a => Arbitrary (MediumNonEmptySeq a) where
arbitrary = MediumNonEmptySeq <$> listOf arbitrary `suchThat` (\l -> length l > 100 && length l < 1000)
dist :: Double -> Double -> Double
dist x y = abs (x-y)
-- | reduce a dataset to half its size by averaging neighbour values
-- together
reduceByHalf :: Fractional a => Seq a -> Seq a
reduceByHalf (S.viewl -> x :< (S.viewl -> y :< xs)) = (x + y) / 2 <| reduceByHalf xs
reduceByHalf (S.viewl -> x :< (S.viewl -> S.EmptyL)) = S.singleton x
reduceByHalf _ = S.empty
{-testDTWVSDTWNaive :: (SmallNonEmptySeq Double, SmallNonEmptySeq Double) -> Bool-}
{-testDTWVSDTWNaive (la,lb) = abs (dtwNaive dist sa sb - dtw dist sa sb) < 0.01-}
{- where sa = S.fromList $ getSmallNonEmpty la-}
{- sb = S.fromList $ getSmallNonEmpty lb-}
testDTWMemoVSDTWNaive :: (SmallNonEmptySeq Double, SmallNonEmptySeq Double) -> Bool
testDTWMemoVSDTWNaive (la,lb) = abs (dtwNaive dist sa sb - cost (dtwMemo dist sa sb)) < 0.01
where sa = S.fromList $ getSmallNonEmpty la
sb = S.fromList $ getSmallNonEmpty lb
testFastDTWvsDTWNaive :: (SmallNonEmptySeq Double, SmallNonEmptySeq Double) -> Bool
testFastDTWvsDTWNaive (la,lb) = abs (1 - (ca/l) / (cb/l)) < 0.1
where sa = S.fromList $ getSmallNonEmpty la
sb = S.fromList $ getSmallNonEmpty lb
l = fromIntegral $ S.length sa + S.length sb
ca = dtwNaive dist sa sb
cb = cost $ fastDtw dist reduceByHalf 2 sa sb
-- FIXME no real idea how to compare an optimal and an approximative
-- algorithm ... best bet below, but still failing tests
{-testFastDTWvsDTWMemo :: (MediumNonEmptySeq Double, MediumNonEmptySeq Double) -> Bool-}
{-testFastDTWvsDTWMemo (la,lb) = abs (1 - ((costA / matSize) / (costB / matSize))) < 0.1-}
{- where sa = S.fromList $ getMediumNonEmpty la-}
{- sb = S.fromList $ getMediumNonEmpty lb-}
{- costA = cost (dtwMemo dist sa sb)-}
{- costB = cost (fastDtw dist 10 sa sb)-}
{- matSize = fromIntegral $ S.length sa * S.length sb-}
main :: IO ()
main = defaultMain
[ testProperty "dtwMemo ≡ dtwNaive" testDTWMemoVSDTWNaive
, testProperty "fastDtw ≅ dtwNaive" testFastDTWvsDTWNaive
{-, testProperty "fastDtw == dtwMemo" testFastDTWvsDTWMemo-}
]