-----------------------------------------------------------------------------
-- |
-- Module      :  ForSyDe.Atom.Skel.Vector.Matrix
-- Copyright   :  (c) George Ungureanu, KTH/EECS/ESY 2019-2020
-- License     :  BSD-style (see the file LICENSE)
-- 
-- Maintainer  :  ugeorge@kth.se
-- Stability   :  experimental
-- Portability :  portable
--
-- This module exports an alias 'Matrix' and a couple of patterns and utilities to
-- work with matrices constructed as 2D vectors. Since names might overlap, this
-- library is recommended to be imported qualified.
-----------------------------------------------------------------------------
module ForSyDe.Atom.Skel.Vector.Matrix where

import Prelude hiding (take, drop)
import qualified Data.List as L
import ForSyDe.Atom.Skel.Vector (Vector(..), vector, fromVector, (<++>))
import qualified ForSyDe.Atom.Skel.Vector as V

-- | 'Matrix' is a type synonym for vector of vectors. This means that /any/ function
-- on 'Vector' works also on 'Matrix'.
type Matrix a = Vector (Vector a)

-- | Prints out to the terminal a matrix in a readable format, where
-- all elements are right-aligned and separated by a custom separator.
--
-- >>> let m = matrix 3 3 [1,2,3,3,100,4,12,32,67]
-- >>> pretty "|" m
--  1|  2| 3
--  3|100| 4
-- 12| 32|67
pretty :: Show a
       => String   -- ^ separator string
       -> Matrix a -- ^ input matrix
       -> IO ()
pretty :: String -> Matrix a -> IO ()
pretty sep :: String
sep mat :: Matrix a
mat = (String -> IO ()) -> [String] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ String -> IO ()
putStrLn ([String] -> IO ()) -> [String] -> IO ()
forall a b. (a -> b) -> a -> b
$ Vector String -> [String]
forall a. Vector a -> [a]
fromVector (Vector String -> [String]) -> Vector String -> [String]
forall a b. (a -> b) -> a -> b
$ Vector Int -> Vector (Vector String) -> Vector String
printMat Vector Int
maxWdt Vector (Vector String)
strMat
  where
    maxWdt :: Vector Int
maxWdt = (Vector Int -> Vector Int -> Vector Int)
-> Vector (Vector Int) -> Vector Int
forall a. (a -> a -> a) -> Vector a -> a
V.reduce ((Int -> Int -> Int) -> Vector Int -> Vector Int -> Vector Int
forall a1 a2 b1.
(a1 -> a2 -> b1) -> Vector a1 -> Vector a2 -> Vector b1
V.farm21 Int -> Int -> Int
forall a. Ord a => a -> a -> a
max) (Vector (Vector Int) -> Vector Int)
-> Vector (Vector Int) -> Vector Int
forall a b. (a -> b) -> a -> b
$ (String -> Int) -> Vector (Vector String) -> Vector (Vector Int)
forall a b. (a -> b) -> Matrix a -> Matrix b
farm11 String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Vector (Vector String)
strMat
    strMat :: Vector (Vector String)
strMat = (a -> String) -> Matrix a -> Vector (Vector String)
forall a b. (a -> b) -> Matrix a -> Matrix b
farm11 a -> String
forall a. Show a => a -> String
show Matrix a
mat
    printMat :: Vector Int -> Vector (Vector String) -> Vector String
printMat w :: Vector Int
w  = (Vector String -> String)
-> Vector (Vector String) -> Vector String
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (Vector Int -> Vector String -> String
printRow Vector Int
w)
    printRow :: Vector Int -> Vector String -> String
printRow w :: Vector Int
w  = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
L.intercalate String
sep ([String] -> String)
-> (Vector String -> [String]) -> Vector String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector String -> [String]
forall a. Vector a -> [a]
fromVector (Vector String -> [String])
-> (Vector String -> Vector String) -> Vector String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> String -> String)
-> Vector Int -> Vector String -> Vector String
forall a1 a2 b1.
(a1 -> a2 -> b1) -> Vector a1 -> Vector a2 -> Vector b1
V.farm21 Int -> String -> String
align Vector Int
w
    align :: Int -> String -> String
align n :: Int
n str :: String
str = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
str) ' ' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
str

-- | Checks if a matrix is null. @<>@ and @<<>>@ are both null matrices.
isNull :: Matrix a -> Bool
isNull :: Matrix a -> Bool
isNull Null = Bool
True
isNull (Null:>Null) = Bool
True
isNull _ = Bool
False

-- | Returns the X and Y dimensions of matrix and checks if it is well formed.
size :: Matrix a -> (Int,Int)
size :: Matrix a -> (Int, Int)
size m :: Matrix a
m = (Int
x,Int
y)
  where
    y :: Int
y = Matrix a -> Int
forall p a. Num p => Vector a -> p
V.length Matrix a
m
    x :: Int
x = (Vector a -> Int
forall p a. Num p => Vector a -> p
V.length (Vector a -> Int) -> (Matrix a -> Vector a) -> Matrix a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Matrix a -> Vector a
forall a. Vector a -> a
V.first) (Matrix a
m)

-- | Checks if a matrix is well-formed, meaning that all its rows are of equal
-- length. Returns the same matrix in case it is well-formed or throws an exception if
-- it is ill-formed.
wellFormed :: Matrix a -> Matrix a
wellFormed :: Matrix a -> Matrix a
wellFormed Null = Matrix a
forall a. Vector a
Null
wellFormed m :: Matrix a
m@(_:>Null) = Matrix a
m
wellFormed m :: Matrix a
m@(x :: Vector a
x:>xs :: Matrix a
xs)
  | (Bool -> Bool -> Bool) -> Vector Bool -> Bool
forall a. (a -> a -> a) -> Vector a -> a
V.reduce Bool -> Bool -> Bool
(&&) ((Vector a -> Bool) -> Matrix a -> Vector Bool
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (\r :: Vector a
r -> Vector a -> Integer
forall p a. Num p => Vector a -> p
V.length Vector a
r Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Vector a -> Integer
forall p a. Num p => Vector a -> p
V.length Vector a
x) Matrix a
xs) = Matrix a
m
  | Bool
otherwise = String -> Matrix a
forall a. HasCallStack => String -> a
error "matrix ill-formed: rows are of unequal lengths"


-- | Converts a list into a 'Matrix'. See example from 'pretty'.
matrix :: Int      -- ^ number of columns (X dimension) @= x@
       -> Int      -- ^ number of rows (Y dimension) @= y@
       -> [a]      -- ^ list of values; /length/ = @x * y@
       -> Matrix a -- ^ 'Matrix' of values; /size/ = @(x,y)@
matrix :: Int -> Int -> [a] -> Matrix a
matrix x :: Int
x y :: Int
y = [Vector a] -> Matrix a
forall a. [a] -> Vector a
vector ([Vector a] -> Matrix a) -> ([a] -> [Vector a]) -> [a] -> Matrix a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([a] -> Vector a) -> [[a]] -> [Vector a]
forall a b. (a -> b) -> [a] -> [b]
map [a] -> Vector a
forall a. [a] -> Vector a
vector ([[a]] -> [Vector a]) -> ([a] -> [[a]]) -> [a] -> [Vector a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [a] -> [[a]]
forall a. Int -> [a] -> [[a]]
groupEvery Int
x ([a] -> [[a]]) -> ([a] -> [a]) -> [a] -> [[a]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall (t :: * -> *) a. Foldable t => t a -> t a
check
  where
    check :: t a -> t a
check l :: t a
l | t a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length t a
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
y = t a
l
            | Bool
otherwise
      = String -> t a
forall a. HasCallStack => String -> a
error (String -> t a) -> String -> t a
forall a b. (a -> b) -> a -> b
$ "matrix: cannot form matrix (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ ","
              String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
y String -> String -> String
forall a. [a] -> [a] -> [a]
++ ") from a list with "
              String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (t a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length t a
l) String -> String -> String
forall a. [a] -> [a] -> [a]
++ " elements"
    groupEvery :: Int -> [a] -> [[a]]
    groupEvery :: Int -> [a] -> [[a]]
groupEvery _ [] = []
    groupEvery n :: Int
n l :: [a]
l
      | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 0        = String -> [[a]]
forall a. HasCallStack => String -> a
error (String -> [[a]]) -> String -> [[a]]
forall a b. (a -> b) -> a -> b
$ "matrix: cannot group list by negative n: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n
      | [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n = String -> [[a]]
forall a. HasCallStack => String -> a
error "matrix: input list cannot be split into all-equal parts"
      | Bool
otherwise    = Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
L.take Int
n [a]
l [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: Int -> [a] -> [[a]]
forall a. Int -> [a] -> [[a]]
groupEvery Int
n (Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
L.drop Int
n [a]
l)

-- | Converts a matrix back to a list.
fromMatrix :: Matrix a -- ^ /size/ = @(x,y)@
           -> [a]      -- ^ /length/ = @x * y@
fromMatrix :: Matrix a -> [a]
fromMatrix = (Vector a -> [a]) -> [Vector a] -> [a]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Vector a -> [a]
forall a. Vector a -> [a]
fromVector ([Vector a] -> [a]) -> (Matrix a -> [Vector a]) -> Matrix a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Matrix a -> [Vector a]
forall a. Vector a -> [a]
fromVector

-- | Creates a unit (i.e. singleton) matrix, which is a matrix with only one element.
unit :: a -> Matrix a -- ^ /size/ = @(1,1)@
unit :: a -> Matrix a
unit a :: a
a = (a
aa -> Vector a -> Vector a
forall a. a -> Vector a -> Vector a
:>Vector a
forall a. Vector a
Null)Vector a -> Matrix a -> Matrix a
forall a. a -> Vector a -> Vector a
:>Matrix a
forall a. Vector a
Null

-- | Creates an /infinite matrix/ which repeats one element
fanout :: a -> Matrix a
fanout :: a -> Matrix a
fanout n :: a
n = Vector a -> Matrix a
forall t. t -> Vector t
V.fanout (Vector a -> Matrix a) -> Vector a -> Matrix a
forall a b. (a -> b) -> a -> b
$ a -> Vector a
forall t. t -> Vector t
V.fanout a
n

-- | Returns an /infinite matrix/ with (X,Y) index pairs. You need to zip it against
-- another (finite) matrix or to extract a finite subset in order to be useful (see
-- example below).
--
-- >>> pretty " " $ take 3 4 indexes 
-- (0,0) (1,0) (2,0)
-- (0,1) (1,1) (2,1)
-- (0,2) (1,2) (2,2)
-- (0,3) (1,3) (2,3)
indexes :: Matrix (Int, Int)
indexes :: Matrix (Int, Int)
indexes = (Int -> Int -> (Int, Int))
-> Vector (Vector Int) -> Vector (Vector Int) -> Matrix (Int, Int)
forall a b c. (a -> b -> c) -> Matrix a -> Matrix b -> Matrix c
farm21 (,) Vector (Vector Int)
colix Vector (Vector Int)
rowix
  where
    colix :: Vector (Vector Int)
colix = [Vector Int] -> Vector (Vector Int)
forall a. [a] -> Vector a
vector ([Vector Int] -> Vector (Vector Int))
-> [Vector Int] -> Vector (Vector Int)
forall a b. (a -> b) -> a -> b
$ Vector Int -> [Vector Int]
forall a. a -> [a]
repeat (Vector Int -> [Vector Int]) -> Vector Int -> [Vector Int]
forall a b. (a -> b) -> a -> b
$ [Int] -> Vector Int
forall a. [a] -> Vector a
vector [0..]
    rowix :: Vector (Vector Int)
rowix = Vector (Vector Int) -> Vector (Vector Int)
forall a. Matrix a -> Matrix a
transpose Vector (Vector Int)
colix

-- | Maps a function on every value of a matrix.
--
-- __OBS:__ this function does not check if the output matrix is well-formed.
farm11 :: (a -> b)
       -> Matrix a -- ^ /size/ = @(xa,ya)@
       -> Matrix b -- ^ /size/ = @(xa,ya)@
farm11 :: (a -> b) -> Matrix a -> Matrix b
farm11 = (Vector a -> Vector b) -> Matrix a -> Matrix b
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 ((Vector a -> Vector b) -> Matrix a -> Matrix b)
-> ((a -> b) -> Vector a -> Vector b)
-> (a -> b)
-> Matrix a
-> Matrix b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> Vector a -> Vector b
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11

-- | Applies a binary function pair-wise on each element in two matrices.
--
-- __OBS:__ this function does not check if the output matrix is well-formed.
farm21 :: (a -> b -> c)
           -> Matrix a -- ^ /size/ = @(xa,ya)@
           -> Matrix b -- ^ /size/ = @(xb,yb)@
           -> Matrix c -- ^ /size/ = @(minimum [xa,xb], minimum [ya,yb])@
farm21 :: (a -> b -> c) -> Matrix a -> Matrix b -> Matrix c
farm21 f :: a -> b -> c
f = (Vector a -> Vector b -> Vector c)
-> Matrix a -> Matrix b -> Matrix c
forall a1 a2 b1.
(a1 -> a2 -> b1) -> Vector a1 -> Vector a2 -> Vector b1
V.farm21 ((a -> b -> c) -> Vector a -> Vector b -> Vector c
forall a1 a2 b1.
(a1 -> a2 -> b1) -> Vector a1 -> Vector a2 -> Vector b1
V.farm21 a -> b -> c
f)

-- | Applies a function 3-tuple-wise on each element in three matrices.
--
-- __OBS:__ this function does not check if the output matrix is well-formed.
farm31 :: (a -> b -> c -> d)
            -> Matrix a -- ^ /size/ = @(xa,ya)@
            -> Matrix b -- ^ /size/ = @(xb,yb)@
            -> Matrix c -- ^ /size/ = @(xc,yc)@
            -> Matrix d -- ^ /size/ = @(minimum [xa,xb,xc], minimum [ya,yb,yc])@
farm31 :: (a -> b -> c -> d) -> Matrix a -> Matrix b -> Matrix c -> Matrix d
farm31 f :: a -> b -> c -> d
f = (Vector a -> Vector b -> Vector c -> Vector d)
-> Matrix a -> Matrix b -> Matrix c -> Matrix d
forall a1 a2 a3 b1.
(a1 -> a2 -> a3 -> b1)
-> Vector a1 -> Vector a2 -> Vector a3 -> Vector b1
V.farm31 ((a -> b -> c -> d) -> Vector a -> Vector b -> Vector c -> Vector d
forall a1 a2 a3 b1.
(a1 -> a2 -> a3 -> b1)
-> Vector a1 -> Vector a2 -> Vector a3 -> Vector b1
V.farm31 a -> b -> c -> d
f)

-- | Reduces all the elements of a matrix to one element based on a
-- binary function.
--
-- >>> let m = matrix 3 3 [1,2,3,11,12,13,21,22,23]
-- >>> reduce (+) m
-- 108
reduce :: (a -> a -> a) -> Matrix a -> a
reduce :: (a -> a -> a) -> Matrix a -> a
reduce f :: a -> a -> a
f = (a -> a -> a) -> Vector a -> a
forall a. (a -> a -> a) -> Vector a -> a
V.reduce a -> a -> a
f (Vector a -> a) -> (Matrix a -> Vector a) -> Matrix a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Vector a -> a) -> Matrix a -> Vector a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 ((a -> a -> a) -> Vector a -> a
forall a. (a -> a -> a) -> Vector a -> a
V.reduce a -> a -> a
f)

-- | Pattern implementing the template for a dot operation between a
-- vector and a matrix.
--
-- >>> let mA = matrix 4 4 [1,-1,1,1,  1,-1,-1,-1,  1,1,-1,1,  1,1,1,-1]
-- >>> let y  = vector[1,0,0,0]
-- >>> dotV (+) (*) mA y
-- <1,1,1,1>
dotV :: (a -> a -> a)
     -- ^ kernel function for a row/column reduction, e.g. @(+)@ for dot product
     -> (b -> a -> a)
     -- ^ binary operation for pair-wise elements, e.g. @(*)@ for dot product
          -> Matrix b      -- ^ /size/ = @(xa,ya)@
          -> Vector a      -- ^ /length/ = @xa@
          -> Vector a      -- ^ /length/ = @xa@
dotV :: (a -> a -> a) -> (b -> a -> a) -> Matrix b -> Vector a -> Vector a
dotV f :: a -> a -> a
f g :: b -> a -> a
g mA :: Matrix b
mA y :: Vector a
y = (Vector b -> a) -> Matrix b -> Vector a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (\x :: Vector b
x -> (a -> a -> a) -> Vector a -> a
forall a. (a -> a -> a) -> Vector a -> a
V.reduce a -> a -> a
f (Vector a -> a) -> Vector a -> a
forall a b. (a -> b) -> a -> b
$ (b -> a -> a) -> Vector b -> Vector a -> Vector a
forall a1 a2 b1.
(a1 -> a2 -> b1) -> Vector a1 -> Vector a2 -> Vector b1
V.farm21 b -> a -> a
g Vector b
x Vector a
y) Matrix b
mA

-- | Pattern implementing the template for a dot operation between two
-- matrices.
--
-- >>> let mA = matrix 4 4 [1,-1,1,1,  1,-1,-1,-1,  1,1,-1,1,  1,1,1,-1]
-- >>> pretty " " $ dot (+) (*) mA mA
-- 2 -2  2  2
-- 2 -2 -2 -2
-- 2  2  2 -2
-- 2  2 -2  2
dot :: (a -> a -> a)
    -- ^ kernel function for a row/column reduction, e.g. @(+)@ for dot product
    -> (b -> a -> a)
    -- ^ binary operation for pair-wise elements, e.g. @(*)@ for dot product
    -> Matrix b      -- ^ /size/ = @(xa,ya)@
    -> Matrix a      -- ^ /size/ = @(ya,xa)@
    -> Matrix a      -- ^ /size/ = @(xa,xa)@
dot :: (a -> a -> a) -> (b -> a -> a) -> Matrix b -> Matrix a -> Matrix a
dot f :: a -> a -> a
f g :: b -> a -> a
g m :: Matrix b
m = (Vector a -> Vector a) -> Matrix a -> Matrix a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 ((a -> a -> a) -> (b -> a -> a) -> Matrix b -> Vector a -> Vector a
forall a b.
(a -> a -> a) -> (b -> a -> a) -> Matrix b -> Vector a -> Vector a
dotV a -> a -> a
f b -> a -> a
g Matrix b
m) (Matrix a -> Matrix a)
-> (Matrix a -> Matrix a) -> Matrix a -> Matrix a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Matrix a -> Matrix a
forall a. Matrix a -> Matrix a
transpose

-- | Returns the element of a matrix at a certain position.
--
-- >>> let m = matrix 3 3 [1,2,3,11,12,13,21,22,23]
-- >>> at 2 1 m
-- 13
get :: Int       -- ^ X index starting from zero
    -> Int       -- ^ Y index starting from zero
    -> Matrix a
    -> Maybe a
get :: Int -> Int -> Matrix a -> Maybe a
get x :: Int
x y :: Int
y mat :: Matrix a
mat = Maybe (Vector a) -> Maybe a
forall a. Maybe (Vector a) -> Maybe a
getMaybe (Int -> Matrix a -> Maybe (Vector a)
forall a. Int -> Vector a -> Maybe a
V.get Int
y Matrix a
mat)
  where getMaybe :: Maybe (Vector a) -> Maybe a
getMaybe Nothing = Maybe a
forall a. Maybe a
Nothing
        getMaybe (Just a :: Vector a
a) = Int -> Vector a -> Maybe a
forall a. Int -> Vector a -> Maybe a
V.get Int
x Vector a
a

-- | Returns the upper-left part of a matrix until a specific
-- position.
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " $ take 2 2 m
--  1  2
-- 11 12
take :: Int       -- ^ X index starting from zero
     -> Int       -- ^ Y index starting from zero
     -> Matrix a
     -> Matrix a
take :: Int -> Int -> Matrix a -> Matrix a
take x :: Int
x y :: Int
y = (Vector a -> Vector a) -> Matrix a -> Matrix a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.take Int
x) (Matrix a -> Matrix a)
-> (Matrix a -> Matrix a) -> Matrix a -> Matrix a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Matrix a -> Matrix a
forall a. Int -> Vector a -> Vector a
V.take Int
y

-- | Returns the upper-left part of a matrix until a specific
-- position.
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " $ drop 2 2 m
-- 23 24
-- 33 34
drop :: Int       -- ^ X index starting from zero
     -> Int       -- ^ Y index starting from zero
     -> Matrix a
     -> Matrix a
drop :: Int -> Int -> Matrix a -> Matrix a
drop x :: Int
x y :: Int
y = (Vector a -> Vector a) -> Matrix a -> Matrix a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.drop Int
x) (Matrix a -> Matrix a)
-> (Matrix a -> Matrix a) -> Matrix a -> Matrix a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Matrix a -> Matrix a
forall a. Int -> Vector a -> Vector a
V.drop Int
y

-- | Crops a section of a matrix.
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " m
--  1  2  3  4
-- 11 12 13 14
-- 21 22 23 24
-- 31 32 33 34
-- >>> pretty " " $ cropMat 2 3 1 1 m
-- 12 13
-- 22 23
-- 32 33
crop :: Int      -- ^ crop width  = @w@
     -> Int      -- ^ crop height = @h@
     -> Int      -- ^ X start position = @x0@
     -> Int      -- ^ Y start position = @y0@
     -> Matrix a -- ^ /size/ = @(xa,ya)@
     -> Matrix a -- ^ /size/ = @(minimum [w,xa-x0], minimum [h,xa-x0])@
crop :: Int -> Int -> Int -> Int -> Matrix a -> Matrix a
crop w :: Int
w h :: Int
h pX :: Int
pX pY :: Int
pY = Int -> Int -> Matrix a -> Matrix a
forall a. Int -> Int -> Matrix a -> Matrix a
take Int
w Int
h (Matrix a -> Matrix a)
-> (Matrix a -> Matrix a) -> Matrix a -> Matrix a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Matrix a -> Matrix a
forall a. Int -> Int -> Matrix a -> Matrix a
drop Int
pX Int
pY

-- cropMat w h pX pY = V.farm11 (crop w pX) . crop h pY
--   where crop size pos = V.drop pos . V.take (pos + size) 

-- | Groups a matrix into smaller equallly-shaped matrices.
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " $ group 2 2 m
--   <<1,2>,<11,12>>   <<3,4>,<13,14>>
-- <<21,22>,<31,32>> <<23,24>,<33,34>>
group :: Int      -- ^ width of groups = @w@
      -> Int      -- ^ height of groups = @h@
      -> Matrix a -- ^ /size/ = @(xa,ya)@
      -> Matrix (Matrix a) -- ^ /size/ = @(xa `div` w,ya `div` h)@
group :: Int -> Int -> Matrix a -> Matrix (Matrix a)
group w :: Int
w h :: Int
h = (Matrix (Vector a) -> Matrix (Vector a))
-> Matrix (Matrix a) -> Matrix (Matrix a)
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 Matrix (Vector a) -> Matrix (Vector a)
forall a. Matrix a -> Matrix a
transpose (Matrix (Matrix a) -> Matrix (Matrix a))
-> (Matrix a -> Matrix (Matrix a)) -> Matrix a -> Matrix (Matrix a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Matrix (Vector a) -> Matrix (Matrix a)
forall a. Int -> Vector a -> Vector (Vector a)
V.group Int
h (Matrix (Vector a) -> Matrix (Matrix a))
-> (Matrix a -> Matrix (Vector a)) -> Matrix a -> Matrix (Matrix a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Vector a -> Matrix a) -> Matrix a -> Matrix (Vector a)
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (Int -> Vector a -> Matrix a
forall a. Int -> Vector a -> Vector (Vector a)
V.group Int
w)


-- | Returns a stencil of neighboring elements for each possible
-- element in a vector.
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " $ stencil 2 2 m
--   <<1,2>,<11,12>>   <<2,3>,<12,13>>   <<3,4>,<13,14>>
-- <<11,12>,<21,22>> <<12,13>,<22,23>> <<13,14>,<23,24>>
-- <<21,22>,<31,32>> <<22,23>,<32,33>> <<23,24>,<33,34>>
stencil :: Int -> Int -> Matrix a -> Matrix (Matrix a)
stencil :: Int -> Int -> Matrix a -> Matrix (Matrix a)
stencil r :: Int
r c :: Int
c = Matrix (Matrix a) -> Matrix (Matrix a)
forall a. Vector (Matrix a) -> Vector (Matrix a)
arrange (Matrix (Matrix a) -> Matrix (Matrix a))
-> (Matrix a -> Matrix (Matrix a)) -> Matrix a -> Matrix (Matrix a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Matrix (Vector a) -> Matrix (Matrix a)
forall a. Matrix (Vector a) -> Matrix (Vector (Vector a))
groupCols (Matrix (Vector a) -> Matrix (Matrix a))
-> (Matrix a -> Matrix (Vector a)) -> Matrix a -> Matrix (Matrix a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Matrix a -> Matrix (Vector a)
forall a. Vector a -> Vector (Vector a)
groupRows
  where
    groupRows :: Vector a -> Vector (Vector a)
groupRows =         (Vector a -> Vector a) -> Vector (Vector a) -> Vector (Vector a)
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.take Int
r) (Vector (Vector a) -> Vector (Vector a))
-> (Vector a -> Vector (Vector a)) -> Vector a -> Vector (Vector a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Vector (Vector a) -> Vector (Vector a)
forall a. Int -> Vector a -> Vector a
dropFromEnd Int
r (Vector (Vector a) -> Vector (Vector a))
-> (Vector a -> Vector (Vector a)) -> Vector a -> Vector (Vector a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector a -> Vector (Vector a)
forall a. Vector a -> Vector (Vector a)
V.tails
    groupCols :: Matrix (Vector a) -> Matrix (Vector (Vector a))
groupCols = (Vector a -> Vector (Vector a))
-> Matrix (Vector a) -> Matrix (Vector (Vector a))
forall a b. (a -> b) -> Matrix a -> Matrix b
farm11 ((Vector a -> Vector a) -> Vector (Vector a) -> Vector (Vector a)
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.take Int
c) (Vector (Vector a) -> Vector (Vector a))
-> (Vector a -> Vector (Vector a)) -> Vector a -> Vector (Vector a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Vector (Vector a) -> Vector (Vector a)
forall a. Int -> Vector a -> Vector a
dropFromEnd Int
c (Vector (Vector a) -> Vector (Vector a))
-> (Vector a -> Vector (Vector a)) -> Vector a -> Vector (Vector a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector a -> Vector (Vector a)
forall a. Vector a -> Vector (Vector a)
V.tails)
    arrange :: Vector (Matrix a) -> Vector (Matrix a)
arrange   = (Matrix a -> Matrix a) -> Vector (Matrix a) -> Vector (Matrix a)
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 Matrix a -> Matrix a
forall a. Matrix a -> Matrix a
transpose
    dropFromEnd :: Int -> Vector a -> Vector a
dropFromEnd n :: Int
n v :: Vector a
v = Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.take (Vector a -> Int
forall p a. Num p => Vector a -> p
V.length Vector a
v Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n) Vector a
v

-- | Reverses the order of elements in a matrix
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " $ reverse m
-- 34 33 32 31
-- 24 23 22 21
-- 14 13 12 11
--  4  3  2  1
reverse :: Matrix a -> Matrix a
reverse :: Matrix a -> Matrix a
reverse = Matrix a -> Matrix a
forall a. Vector a -> Vector a
V.reverse (Matrix a -> Matrix a)
-> (Matrix a -> Matrix a) -> Matrix a -> Matrix a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Vector a -> Vector a) -> Matrix a -> Matrix a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 Vector a -> Vector a
forall a. Vector a -> Vector a
V.reverse

-- | Pattern which "rotates" a matrix. The rotation is controled with
-- the /x/ and /y/ index arguments as following:
--
-- * @(> 0)@ : rotates the matrix right/down with the corresponding
-- number of positions.
-- 
-- * @(= 0)@ : does not modify the position for that axis.
-- 
-- * @(< 0)@ : rotates the matrix left/up with the corresponding
-- number of positions.
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " $ rotate (-1) 1 m
-- 32 33 34 31
--  2  3  4  1
-- 12 13 14 11
-- 22 23 24 21
rotate :: Int -- ^ index on X axis
       -> Int -- ^ index on Y axis
       -> Matrix a
       -> Matrix a
rotate :: Int -> Int -> Matrix a -> Matrix a
rotate x :: Int
x y :: Int
y = Int -> Matrix a -> Matrix a
forall a. Int -> Vector a -> Vector a
V.rotate Int
y (Matrix a -> Matrix a)
-> (Matrix a -> Matrix a) -> Matrix a -> Matrix a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Vector a -> Vector a) -> Matrix a -> Matrix a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 (Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.rotate Int
x)

-- | Transposes a matrix
--
-- >>> let m = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> pretty " " $ transpose m
-- 1 11 21 31
-- 2 12 22 32
-- 3 13 23 33
-- 4 14 24 34
transpose :: Matrix a     -- ^ @X:Y@ orientation
          -> Matrix a     -- ^ @Y:X@ orientation
transpose :: Matrix a -> Matrix a
transpose Null = Matrix a
forall a. Vector a
Null
transpose (Null:>xss :: Matrix a
xss) = Matrix a -> Matrix a
forall a. Matrix a -> Matrix a
transpose Matrix a
xss
transpose rows :: Matrix a
rows = ((Vector a -> a) -> Matrix a -> Vector a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 Vector a -> a
forall a. Vector a -> a
V.first Matrix a
rows) Vector a -> Matrix a -> Matrix a
forall a. a -> Vector a -> Vector a
:> Matrix a -> Matrix a
forall a. Matrix a -> Matrix a
transpose ((Vector a -> Vector a) -> Matrix a -> Matrix a
forall a1 b1. (a1 -> b1) -> Vector a1 -> Vector b1
V.farm11 Vector a -> Vector a
forall a. Vector a -> Vector a
V.tail Matrix a
rows)
-- transpose = V.reduce (V.farm21 (<++>)) . farm11 V.unit   -- stack overflow!


-- | Replaces a part of matrix with another (smaller) part, starting
-- from an arbitrary position.
--
-- >>> let m  = matrix 4 4 [1,2,3,4,11,12,13,14,21,22,23,24,31,32,33,34]
-- >>> let m1 = matrix 2 2 [101,202,303,404]
-- >>> pretty " " $ replace 1 1 m1 m
--  1   2   3  4
-- 11 101 202 14
-- 21 303 404 24
-- 31  32  33 34
replace :: Int -> Int -> Matrix a -> Matrix a -> Matrix a
replace :: Int -> Int -> Matrix a -> Matrix a -> Matrix a
replace x :: Int
x y :: Int
y mask :: Matrix a
mask = Int -> Int -> (Matrix a -> Matrix a) -> Matrix a -> Matrix a
forall a.
Int -> Int -> (Vector a -> Vector a) -> Vector a -> Vector a
replace Int
y Int
h ((Vector a -> Vector a -> Vector a)
-> Matrix a -> Matrix a -> Matrix a
forall a1 a2 b1.
(a1 -> a2 -> b1) -> Vector a1 -> Vector a2 -> Vector b1
V.farm21 (\m :: Vector a
m o :: Vector a
o -> Int -> Int -> (Vector a -> Vector a) -> Vector a -> Vector a
forall a.
Int -> Int -> (Vector a -> Vector a) -> Vector a -> Vector a
replace Int
x Int
w (Vector a -> Vector a -> Vector a
forall a b. a -> b -> a
const Vector a
m) Vector a
o) Matrix a
mask)
  where
    (w :: Int
w,h :: Int
h) = Matrix a -> (Int, Int)
forall a. Matrix a -> (Int, Int)
size Matrix a
mask
    replace :: Int -> Int -> (Vector a -> Vector a) -> Vector a -> Vector a
replace start :: Int
start size :: Int
size replaceF :: Vector a -> Vector a
replaceF vec :: Vector a
vec
      = let begin :: Vector a
begin  = Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.take Int
start Vector a
vec
            middle :: Vector a
middle = Vector a -> Vector a
replaceF (Vector a -> Vector a) -> Vector a -> Vector a
forall a b. (a -> b) -> a -> b
$ Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.drop Int
start (Vector a -> Vector a) -> Vector a -> Vector a
forall a b. (a -> b) -> a -> b
$ Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.take (Int
start Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
size) Vector a
vec
            end :: Vector a
end    = Int -> Vector a -> Vector a
forall a. Int -> Vector a -> Vector a
V.drop (Int
start Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
size) Vector a
vec
        in Vector a
begin Vector a -> Vector a -> Vector a
forall a. Vector a -> Vector a -> Vector a
<++> Vector a
middle Vector a -> Vector a -> Vector a
forall a. Vector a -> Vector a -> Vector a
<++> Vector a
end