packages feed

matrix-0.3.4.0: test/Main.hs

import Data.Matrix
import Data.Ratio
import Control.Applicative
import Data.Monoid (mconcat)

import Test.Tasty
import qualified Test.Tasty.QuickCheck as QC
import Test.QuickCheck

{- matrix package test set

This program uses QuickCheck to check that the matrix
functions of the matrix package are working properly.

We use the type Rational to have avoid numerical errors
that may cause the test to fail while the algorithm is
correct.

-}

-- | Numbers used in tests.
type R = Rational

newtype I = I { fromI :: Int }

instance Show I where
  show (I n) = show n

instance Arbitrary I where
  arbitrary = I <$> choose (1,9)

instance Arbitrary a => Arbitrary (Matrix a) where
  arbitrary = do
    I n <- arbitrary
    I m <- arbitrary
    genMatrix' n m

genMatrix' :: Arbitrary a => Int -> Int -> Gen (Matrix a)
genMatrix' n m = fromList n m <$> vector (n*m)

genMatrix :: Int -> Int -> Gen (Matrix R)
genMatrix = genMatrix'

-- | Square matrices
newtype Sq = Sq { fromSq :: Matrix R }

instance Show Sq where
  show (Sq m) = show m

instance Arbitrary Sq where
  arbitrary = do
    I n <- arbitrary
    Sq <$> genMatrix n n

main :: IO ()
main = defaultMain $ testGroup "matrix tests" [
    QC.testProperty "zero n m = matrix n m (const 0)"
       $ \(I n) (I m) -> zero n m == matrix n m (const 0)
  , QC.testProperty "identity * m = m * identity = m"
       $ \(Sq m) -> let n = nrows m in identity n * m == m && m * identity n == m
  , QC.testProperty "a * (b * c) = (a * b) * c"
       $ \(I a) (I b) (I c) (I d) -> forAll (genMatrix a b)
       $ \m1 -> forAll (genMatrix b c)
       $ \m2 -> forAll (genMatrix c d)
       $ \m3 -> m1 * (m2 * m3) == (m1 * m2) * m3
  , QC.testProperty "multStd a b = multStd2 a b"
       $ \(I a) (I b) (I c) -> forAll (genMatrix a b)
       $ \m1 -> forAll (genMatrix b c)
       $ \m2 -> multStd m1 m2 == multStd2 m1 m2
  , QC.testProperty "getMatrixAsVector m = mconcat [ getRow i m | i <- [1 .. nrows m]]"
       $ \m -> getMatrixAsVector (m :: Matrix R) == mconcat [ getRow i m | i <- [1 .. nrows m] ]
  , QC.testProperty "fmap id = id"
       $ \m -> fmap id m == (m :: Matrix R)
  , QC.testProperty "permMatrix n i j * permMatrix n i j = identity n"
       $ \(I n) -> forAll (choose (1,n))
       $ \i     -> forAll (choose (1,n))
       $ \j     -> permMatrix n i j * permMatrix n i j == identity n
  , QC.testProperty "setElem (getElem i j m) (i,j) m = m"
       $ \m -> forAll (choose (1,nrows m))
       $ \i -> forAll (choose (1,ncols m))
       $ \j -> setElem (getElem i j m) (i,j) m == (m :: Matrix R)
  , QC.testProperty "transpose (transpose m) = m"
       $ \m -> transpose (transpose m) == (m :: Matrix R)
  , QC.testProperty "if m' = setSize e r c m then (nrows m' = r) && (ncols m' = c)"
       $ \e (I r) (I c) m -> let m' :: Matrix R ; m' = setSize e r c m in nrows m' == r && ncols m' == c
  , QC.testProperty "if (nrows m = r) && (nrcols m = c) then setSize _ r c m = m"
       $ \m -> let r = nrows m
                   c = ncols m
               in  setSize undefined r c m == (m :: Matrix R)
  , QC.testProperty "getRow i m = getCol i (transpose m)"
       $ \m -> forAll (choose (1,nrows m))
       $ \i -> getRow i (m :: Matrix R) == getCol i (transpose m)
  , QC.testProperty "joinBlocks (splitBlocks i j m) = m"
       $ \m -> forAll (choose (1,nrows m))
       $ \i -> forAll (choose (1,ncols m))
       $ \j -> joinBlocks (splitBlocks i j m) == (m :: Matrix R)
  , QC.testProperty "scaleMatrix k m = fmap (*k) m"
       $ \k m -> scaleMatrix k m == fmap (*k) (m :: Matrix R)
  , QC.testProperty "(+) = elementwise (+)"
       $ \m1 -> forAll (genMatrix (nrows m1) (ncols m1))
       $ \m2 -> m1 + m2 == elementwise (+) m1 m2
  , QC.testProperty "switchCols i j = transpose . switchRows i j . transpose"
       $ \m -> forAll (choose (1,ncols m))
       $ \i -> forAll (choose (1,ncols m))
       $ \j -> switchCols i j (m :: Matrix R) == (transpose $ switchRows i j $ transpose m)
  , QC.testProperty "detLaplace (fromList 3 3 $ repeat 1) = 0"
       $ detLaplace (fromList 3 3 $ repeat 1) == 0
  , QC.testProperty "if (u,l,p,d) = luDecomp m then (p*m = l*u) && (detLaplace p = d)"
       $ \(Sq m) -> (detLaplace m /= 0) ==>
             (let (u,l,p,d) = luDecompUnsafe m in p*m == l*u && detLaplace p == d)
  , QC.testProperty "detLaplace m = detLU m"
       $ \(Sq m) -> detLaplace m == detLU m
  , QC.testProperty "if (u,l,p,q,d,e) = luDecomp' m then (p*m*q = l*u) && (detLU p = d) && (detLU q = e)"
       $ \(Sq m) -> (detLU m /= 0) ==>
             (let (u,l,p,q,d,e) = luDecompUnsafe' m in p*m*q == l*u && detLU p == d && detLU q == e)
  , QC.testProperty "detLU (scaleRow k i m) = k * detLU m"
       $ \(Sq m) k -> forAll (choose (1,nrows m))
       $ \i -> detLU (scaleRow k i m) == k * detLU m
  , QC.testProperty "let n = nrows m in detLU (switchRows i j m) = detLU (permMatrix n i j) * detLU m"
       $ \(Sq m) -> let n = nrows m in forAll (choose (1,n))
       $ \i      -> forAll (choose (1,n))
       $ \j      -> detLU (switchRows i j m) == detLU (permMatrix n i j) * detLU m
  , QC.testProperty "fromList n m . toList = id"
       $ \m -> fromList (nrows m) (ncols m) (toList m) == (m :: Matrix R)
  , QC.testProperty "fromLists . toLists = id"
       $ \m -> fromLists (toLists m) == (m :: Matrix R)
    ]