packages feed

blas-0.6: tests/Matrix.hs

{-# LANGUAGE PatternSignatures #-}

module Matrix( tests_Matrix ) where

import Driver
import qualified Data.Array as Array

import BLAS.Elem
import Data.Matrix.Dense
import Data.Vector.Dense

import Generators.Matrix.Dense hiding ( matrix )
        

type V = Vector Int E
type M = Matrix (Int,Int) E


prop_matrix_shape (Assocs2 mn ijes) =
    shape (matrix mn ijes :: M) == mn
prop_matrix_assocs (Assocs2 (m,n) ijes) =
    assocs (matrix (m,n) ijes :: M) 
    `assocsEq` 
    (zip (range ((0,0),(m-1,n-1))) (repeat 0) ++ ijes)

prop_listMatrix_shape (Nat2 mn) es =
    shape (listMatrix mn es :: M) == mn
prop_listMatrix_assocs (Nat2 (m,n)) es =
    let es' = repeat es
    in assocs (listMatrix (m,n) es' :: M) 
       === 
       zip [(i,j) | j <- range (0,n-1), i <- range (0,m-1)] es'

prop_zero_shape (Nat2 mn) =
    shape (zeroMatrix mn :: M) == mn
prop_zero_elems (Nat2 (m,n)) =
    elems (zeroMatrix (m,n) :: M) == replicate (m*n) 0

prop_constant_shape (Nat2 mn) (e :: E) =
    shape (constantMatrix mn e :: M) == mn
prop_constant_elems (Nat2 (m,n)) (e :: E) =
    elems (constantMatrix (m,n) e :: M) == replicate (m*n) e

prop_identityMatrix_shape (Nat2 mn) =
    shape (identityMatrix mn :: M) == mn
prop_identityMatrix_diag (Nat2 (m,n)) =
    diag (identityMatrix (m,n) :: M) 0 === (constantVector (min m n) 1)
prop_identityMatrix_row (Index i m) (Index _ n) =
    if i < min m n 
        then row (identityMatrix (m,n) :: M) i === basisVector n i
        else row (identityMatrix (m,n) :: M) i === zeroVector n
prop_identityMatrix_col (Index _ m) (Index j n) =
    if j < min m n
        then col (identityMatrix (m,n) :: M) j === basisVector m j
        else col (identityMatrix (m,n) :: M) j === zeroVector m

prop_replace_elems (a :: M) (Assocs2 _ ijes) =
    let ijes' = filter (\((i,j),_) -> i < numRows a && j < numCols a) ijes
        a'   = a // ijes'
        mn   = (numRows a - 1, numCols a - 1)
    in and $ zipWith (\(ij1,e1) (ij2,e2) -> (ij1 == ij2) && (e1 === e2))
                     (sortBy (comparing fst) $ assocs a')
                     (Array.assocs $ (Array.//) (Array.array ((0,0),mn) $ assocs a) ijes')


prop_submatrix_shape (SubMatrix a ij mn) =
    shape (submatrix a ij mn :: M) == mn
prop_submatrix_rows (SubMatrix a (i,j) (m,n)) =
    rows (submatrix a (i,j) (m,n) :: M) === map (\k -> subvector (row a (i+k)) j n) [0..(m-1)]
prop_submatrix_cols (SubMatrix a (i,j) (m,n)) =
    cols (submatrix a (i,j) (m,n) :: M) === map (\l -> subvector (col a (j+l)) i m) [0..(n-1)]

prop_shape (a :: M) = 
    shape a == (numRows a, numCols a)
prop_size (a :: M) =
    size a == numRows a * numCols a
prop_bounds (a :: M) =
    bounds a == ((0,0), (numRows a - 1, numCols a - 1))
    
prop_at (MatrixAt (a :: M) (i,j)) =
    let ij = (i,j)
        k  = if isHermMatrix a then j + i * numCols a
                               else i + j * numRows a
    in (a!ij) === ((elems a) !! k)
    
prop_row_dim (MatrixAt (a :: M) (i,_)) =
    dim (row a i) == numCols a
prop_col_dim (MatrixAt (a :: M) (_,j)) =
    dim (col a j) == numRows a
    
prop_rows_len (a :: M) =
    length (rows a) == numRows a
prop_cols_len (a :: M) =
    length (cols a) == numCols a
prop_rows_dims (a :: M) =
    map dim (rows a) == replicate (numRows a) (numCols a)
prop_cols_dims (a :: M) =
    map dim (cols a) == replicate (numCols a) (numRows a)

prop_indices (a :: M)
    | isHermMatrix a =
        indices a == [(i,j) | i <- range (0,m-1), j <- range(0,n-1)]
    | otherwise =
        indices a == [(i,j) | j <- range (0,n-1), i <- range(0,m-1)]
  where (m,n) = shape a
  
prop_elems (a :: M) 
    | isHermMatrix a =
        elems a === concatMap elems (rows a)        
    | otherwise =
        elems a === concatMap elems (cols a)
        
prop_assocs (a :: M) = 
    assocs a === zip (indices a) (elems a)

prop_scale_elems (a :: M) k =
    and $ zipWith (~==) (elems (k *> a)) (map (k*) (elems a))
prop_herm_elem (MatrixAt (a :: M) (i,j)) =
    (herm a) ! (j,i) == conj (a!(i,j))
prop_herm_scale (a :: M) k =
    herm (k *> a) === (conj k) *> (herm a)

prop_herm_shape (a :: M) =
    shape (herm a) == (numCols a, numRows a)
prop_herm_rows (a :: M) =
    rows (herm a) === map conj (cols a)
prop_herm_cols (a :: M) = 
    cols (herm a) === map conj (rows a)

prop_herm_herm (a :: M) =
    herm (herm a) === a

prop_diag_herm1 (MatrixAt (a :: M) (k,_)) =
    diag a (-k) === conj (diag (herm a) k)
prop_diag_herm2 (MatrixAt (a :: M) (_,k)) =
    diag a k === conj (diag (herm a) (-k))

prop_rowMatrix_shape (x :: V) =
    shape (rowMatrix x :: M) == (1,dim x)
prop_rowMatrix_elems (x :: V) =
    elems (rowMatrix x :: M) === elems x

prop_colMatrix_shape (x :: V) =
    shape (colMatrix x :: M) == (dim x,1)
prop_colMatrix_elems (x :: V) =
    elems (colMatrix x :: M) === elems x

prop_apply_basis (MatrixAt (a :: M) (_,j)) =
    a <*> (basisVector (numCols a) j :: V) ~== col a j
prop_apply_herm_basis (MatrixAt (a :: M) (i,_)) =
    (herm a) <*> (basisVector (numRows a) i :: V) ~== conj (row a i)
prop_apply_scale k (MatrixMV (a :: M) x) =
    sapply k a x ~== k *> (a <*> x)
prop_apply_linear (MatrixMVPair (a :: M) x y) =
    a <*> (x + y) ~== a <*> x + a <*> y

prop_applyMat_id_right (a :: M) =
    let n = numCols a
    in a <**> (identityMatrix (n,n) :: M) ~== a
prop_applyMat_id_left (a :: M) =
    let m = numRows a
    in (identityMatrix (m,m) :: M) <**> a ~== a
prop_applyMat_scale_left (MatrixMM (a:: M) b) k =
    a <**> (k *> b) ~== k *> (a <**> b)    
prop_applyMat_scale_right (MatrixMM (a:: M) b) k =
    (k *> a) <**> b ~== k *> (a <**> b)
prop_applyMat_linear (MatrixMMPair (a :: M) b c) =
    a <**> (b + c) ~== a <**> b + a <**> c
prop_applyMat_herm (MatrixMM (a :: M) b) =
    herm b <**> herm a ~== herm (a <**> b)
prop_applyMat_cols (MatrixMM (a :: M) b) =
    cols (a <**> b) ~== map (a <*> ) (cols b)

prop_shift k (a :: M) =
    shift k a ~== a + constantMatrix (shape a) k
prop_scale k (a :: M) =
    k *> a ~== a * constantMatrix (shape a) k

prop_plus (MatrixPair (a :: M) b) =
    colElems (a + b) ~== zipWith (+) (colElems a) (colElems b)
prop_minus (MatrixPair (a :: M) b) =
    colElems (a - b) ~== zipWith (-) (colElems a) (colElems b)
prop_times (MatrixPair (a :: M) b) =
    colElems (a * b) ~== zipWith (*) (colElems a) (colElems b)
prop_divide (MatrixPair (a :: M) b) =
    colElems (a / b) ~== zipWith (/) (colElems a) (colElems b)

colElems a = concatMap elems (cols a)

prop_negate (a :: M) =
    negate a ~== (-1) *> a
    
prop_abs (a :: M) =
    elems (abs a) ~== map abs (elems a)
prop_signum (a :: M) =
    elems (signum a) === map signum (elems a)
prop_recip (a :: M) =
    elems (recip a) ~== (map recip $ elems a)

tests_Matrix =
    [ ("shape of matrix"       , mytest prop_matrix_shape)
    , ("assocs of matrix"      , mytest prop_matrix_assocs)
    , ("shape of listMatrix"   , mytest prop_listMatrix_shape)
    , ("assocs of listMatrix"  , mytest prop_listMatrix_assocs)
    , ("shape of zero"         , mytest prop_zero_shape)
    , ("elems of zero"         , mytest prop_zero_elems)
    
    , ("shape of constant"     , mytest prop_constant_shape)
    , ("elems of constant"     , mytest prop_constant_elems)
    
    , ("shape of identityMatrix"     , mytest prop_identityMatrix_shape)
    , ("diag of identityMatrix"      , mytest prop_identityMatrix_diag)
    , ("row of identityMatrix"       , mytest prop_identityMatrix_row)
    , ("col of identityMatrix"       , mytest prop_identityMatrix_col)
    
    , ("elems of replace"      , mytest prop_replace_elems)
    
    , ("numRows/numCols"       , mytest prop_shape)
    , ("size"                  , mytest prop_size)
    , ("bounds"                , mytest prop_bounds)
    , ("at"                    , mytest prop_at)
    , ("row dim"               , mytest prop_row_dim)
    , ("col dim"               , mytest prop_col_dim)
    , ("rows length"           , mytest prop_rows_len)
    , ("cols length"           , mytest prop_cols_len)
    , ("rows dims"             , mytest prop_rows_dims)
    , ("cols dims"             , mytest prop_cols_dims)

    , ("indices"               , mytest prop_indices)
    , ("elems"                 , mytest prop_elems)
    , ("assocs"                , mytest prop_assocs)
    
    , ("shape of submatrix"    , mytest prop_submatrix_shape)
    , ("rows of submatrix"     , mytest prop_submatrix_rows)
    , ("col of submatrix"      , mytest prop_submatrix_cols)
    
    , ("elems of scale"        , mytest prop_scale_elems)
    , ("elem of herm"          , mytest prop_herm_elem)
    , ("herm/scale"            , mytest prop_herm_scale)
                               
    , ("shape . herm"          , mytest prop_herm_shape)
    , ("rows . herm"           , mytest prop_herm_rows)
    , ("cols . herm"           , mytest prop_herm_cols)
                               
    , ("herm . herm == id"     , mytest prop_herm_herm)
                               
    , ("subdiag . herm"        , mytest prop_diag_herm1)
    , ("superdiag . herm"      , mytest prop_diag_herm2)
                               
    , ("shape . rowMatrix"       , mytest prop_rowMatrix_shape)
    , ("elems . rowMatrix"       , mytest prop_rowMatrix_elems)
    , ("shape . colMatrix"       , mytest prop_colMatrix_shape)
    , ("elems . colMatrix"       , mytest prop_colMatrix_elems)

    , ("apply basis"           , mytest prop_apply_basis)
    , ("apply herm basis"      , mytest prop_apply_herm_basis)
    , ("apply scale"           , mytest prop_apply_scale)
    , ("apply linear"          , mytest prop_apply_linear)
    
    , ("applyMat id left"       , mytest prop_applyMat_id_left)
    , ("applyMat id right"      , mytest prop_applyMat_id_right)
    , ("applyMat scale left"    , mytest prop_applyMat_scale_left)
    , ("applyMat scale right"   , mytest prop_applyMat_scale_right)
    , ("applyMat linear"        , mytest prop_applyMat_linear)
    , ("applyMat herm"          , mytest prop_applyMat_herm)
    , ("applyMat cols"          , mytest prop_applyMat_cols)
    , ("shift"                 , mytest prop_shift)
    , ("scale"                 , mytest prop_scale)
    
    , ("plus"                  , mytest prop_plus)
    , ("minus"                 , mytest prop_minus)
    , ("times"                 , mytest prop_times)
    , ("divide"                , mytest prop_divide)
    
    , ("negate"                , mytest prop_negate)
    , ("abs"                   , mytest prop_abs)
    , ("signum"                , mytest prop_signum)
    , ("recip"                 , mytest prop_recip)
    ]


assocsEq :: [((Int,Int), E)] -> [((Int,Int), E)] -> Bool
assocsEq ies ies' = ordered ies ~== ordered ies'
  where
    ordered = sortAssocs . nubAssocs
    nubAssocs = reverse . nubBy ((==) `on` fst) . reverse      
    sortAssocs = sortBy (comparing fst)