-- |
-- Module    : Statistics.Matrix.Types
-- Copyright : 2014 Bryan O'Sullivan
-- License   : BSD3
--
-- Basic matrix operations.
--
-- There isn't a widely used matrix package for Haskell yet, so
-- we implement the necessary minimum here.

module Statistics.Matrix.Types
    (
      Vector
    , MVector
    , Matrix(..)
    , MMatrix(..)
    , debug
    ) where

import Data.Char (isSpace)
import Numeric (showFFloat)
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as M

type Vector = U.Vector Double
type MVector s = M.MVector s Double

-- | Two-dimensional matrix, stored in row-major order.
data Matrix = Matrix {
      Matrix -> Int
rows     :: {-# UNPACK #-} !Int -- ^ Rows of matrix.
    , Matrix -> Int
cols     :: {-# UNPACK #-} !Int -- ^ Columns of matrix.
    , Matrix -> Vector
_vector  :: !Vector             -- ^ Matrix data.
    } deriving (Matrix -> Matrix -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Matrix -> Matrix -> Bool
$c/= :: Matrix -> Matrix -> Bool
== :: Matrix -> Matrix -> Bool
$c== :: Matrix -> Matrix -> Bool
Eq)

-- | Two-dimensional mutable matrix, stored in row-major order.
data MMatrix s = MMatrix
                 {-# UNPACK #-} !Int
                 {-# UNPACK #-} !Int
                 !(MVector s)

-- The Show instance is useful only for debugging.
instance Show Matrix where
    show :: Matrix -> String
show = Matrix -> String
debug

debug :: Matrix -> String
debug :: Matrix -> String
debug (Matrix Int
r Int
c Vector
vs) = [String] -> String
unlines forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall a. [a] -> [a] -> [a]
(++) (String
hdr0 forall a. a -> [a] -> [a]
: forall a. a -> [a]
repeat String
hdr) [String]
rrows
  where
    rrows :: [String]
rrows         = forall a b. (a -> b) -> [a] -> [b]
map (ShowS
cleanEnd forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
unwords) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a}. [a] -> [[a]]
split forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith forall a. [a] -> [a] -> [a]
(++) [String]
ldone [String]
tdone
    hdr0 :: String
hdr0          = forall a. Show a => a -> String
show (Int
r,Int
c) forall a. [a] -> [a] -> [a]
++ String
" "
    hdr :: String
hdr           = forall a. Int -> a -> [a]
replicate (forall (t :: * -> *) a. Foldable t => t a -> Int
length String
hdr0) Char
' '
    pad :: (String -> t a -> t) -> Int -> t a -> t
pad String -> t a -> t
plus Int
k t a
xs = forall a. Int -> a -> [a]
replicate (Int
k forall a. Num a => a -> a -> a
- forall (t :: * -> *) a. Foldable t => t a -> Int
length t a
xs) Char
' ' String -> t a -> t
`plus` t a
xs
    ldone :: [String]
ldone         = forall a b. (a -> b) -> [a] -> [b]
map (forall {t :: * -> *} {a} {t}.
Foldable t =>
(String -> t a -> t) -> Int -> t a -> t
pad forall a. [a] -> [a] -> [a]
(++) (forall {a}. [[a]] -> Int
longest [String]
lstr)) [String]
lstr
    tdone :: [String]
tdone         = forall a b. (a -> b) -> [a] -> [b]
map (forall {t :: * -> *} {a} {t}.
Foldable t =>
(String -> t a -> t) -> Int -> t a -> t
pad (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. [a] -> [a] -> [a]
(++)) (forall {a}. [[a]] -> Int
longest [String]
tstr)) [String]
tstr
    ([String]
lstr, [String]
tstr)  = forall a b. [(a, b)] -> ([a], [b])
unzip forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
==Char
'.') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {a}. RealFloat a => a -> String
render) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Unbox a => Vector a -> [a]
U.toList forall a b. (a -> b) -> a -> b
$ Vector
vs
    longest :: [[a]] -> Int
longest       = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall (t :: * -> *) a. Foldable t => t a -> Int
length
    render :: a -> String
render a
k      = forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
==Char
'.') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
==Char
'0') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                    forall a. RealFloat a => Maybe Int -> a -> ShowS
showFFloat (forall a. a -> Maybe a
Just Int
4) a
k forall a b. (a -> b) -> a -> b
$ String
""
    split :: [a] -> [[a]]
split []      = []
    split [a]
xs      = [a]
i forall a. a -> [a] -> [a]
: [a] -> [[a]]
split [a]
rest where ([a]
i, [a]
rest) = forall a. Int -> [a] -> ([a], [a])
splitAt Int
c [a]
xs
    cleanEnd :: ShowS
cleanEnd      = forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
reverse