{-# LANGUAGE FlexibleInstances #-}

module Data.Matrix.Class where

import Prelude ()
import Algebra.RingUtils
import Control.Applicative hiding ((<|>))


fingerprint :: m a -> [[Char]]
fingerprint m a
m = [[ if a -> Bool
forall a. AbelianGroupZ a => a -> Bool
isZero (Int -> Int -> m a -> a
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Int -> Int -> m a -> a
at Int
i Int
j m a
m) then Char
' ' else Char
'X' | Int
i <- [Int
0..Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1] ] | Int
j <- [Int
0..Int
yInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1]]
  where x :: Int
x = m a -> Int
forall (m :: * -> *) a. Matrix m => m a -> Int
countColumns m a
m
        y :: Int
y = m a -> Int
forall (m :: * -> *) a. Matrix m => m a -> Int
countRows m a
m

(t -> a
f *** :: (t -> a) -> (t -> b) -> (t, t) -> (a, b)
*** t -> b
g) (t
x,t
y) = (t -> a
f t
x,t -> b
g t
y)

data Dimension
    = XD
    | YD
      deriving (Dimension -> Dimension -> Bool
(Dimension -> Dimension -> Bool)
-> (Dimension -> Dimension -> Bool) -> Eq Dimension
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Dimension -> Dimension -> Bool
$c/= :: Dimension -> Dimension -> Bool
== :: Dimension -> Dimension -> Bool
$c== :: Dimension -> Dimension -> Bool
Eq,Int -> Dimension -> ShowS
[Dimension] -> ShowS
Dimension -> [Char]
(Int -> Dimension -> ShowS)
-> (Dimension -> [Char])
-> ([Dimension] -> ShowS)
-> Show Dimension
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [Dimension] -> ShowS
$cshowList :: [Dimension] -> ShowS
show :: Dimension -> [Char]
$cshow :: Dimension -> [Char]
showsPrec :: Int -> Dimension -> ShowS
$cshowsPrec :: Int -> Dimension -> ShowS
Show)

quad :: m a -> m a -> m a -> m a -> m a
quad m a
a m a
b m a
c m a
d = (m a
a m a -> m a -> m a
forall a (m :: * -> *).
(AbelianGroup a, Matrix m) =>
m a -> m a -> m a
<|> m a
b) m a -> m a -> m a
forall a (m :: * -> *).
(AbelianGroup a, Matrix m) =>
m a -> m a -> m a
<-> (m a
c m a -> m a -> m a
forall a (m :: * -> *).
(AbelianGroup a, Matrix m) =>
m a -> m a -> m a
<|> m a
d)


nextDim :: Dimension -> Dimension
nextDim Dimension
XD = Dimension
YD
nextDim Dimension
YD = Dimension
XD

type Extent = (Int,Int)

ext :: Dimension -> (a, a) -> a
ext Dimension
XD (a
x,a
y) = a
x
ext Dimension
YD (a
x,a
y) = a
y

glueExt :: Dimension -> (a, b) -> (a, b) -> (a, b)
glueExt Dimension
XD (a
x1,b
y1) (a
x2,b
y2)  = (a
x1a -> a -> a
forall a. AbelianGroup a => a -> a -> a
+a
x2,b
y1)
glueExt Dimension
YD (a
x1,b
y1) (a
x2,b
y2)  = (a
x1,b
y1b -> b -> b
forall a. AbelianGroup a => a -> a -> a
+b
y2)

splitExt :: Dimension -> b -> (b, b) -> ((b, b), (b, b))
splitExt Dimension
XD b
k (b
x,b
y) = ((b
k,b
y),(b
xb -> b -> b
forall a. Num a => a -> a -> a
-b
k,b
y))
splitExt Dimension
YD b
k (b
x,b
y) = ((b
x,b
k),(b
x,b
yb -> b -> b
forall a. Num a => a -> a -> a
-b
k))

class Matrix m where
  at :: AbelianGroupZ a => Int -> Int -> m a -> a
  extent :: m a -> Extent
  -- | Sigleton matrix
  singleton :: AbelianGroupZ a => a -> m a
  glue :: AbelianGroup a => Dimension -> m a -> m a -> m a
  split :: AbelianGroupZ a => Dimension -> Int -> m a -> (m a, m a)
  zeroMatrix :: AbelianGroup a => Int -> Int -> m a

instance Matrix m => Matrix (O Pair m) where
  at :: forall a. AbelianGroupZ a => Int -> Int -> O Pair m a -> a
at Int
i Int
j (O (m a
x :/: m a
y)) = Int -> Int -> m a -> a
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Int -> Int -> m a -> a
at Int
i Int
j m a
x a -> a -> a
forall a. AbelianGroup a => a -> a -> a
+ Int -> Int -> m a -> a
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Int -> Int -> m a -> a
at Int
i Int
j m a
y
  extent :: forall a. O Pair m a -> Extent
extent (O (m a
x :/: m a
y)) = m a -> Extent
forall (m :: * -> *) a. Matrix m => m a -> Extent
extent m a
x -- union with y
  glue :: forall a.
AbelianGroup a =>
Dimension -> O Pair m a -> O Pair m a -> O Pair m a
glue Dimension
d (O Pair (m a)
p) (O Pair (m a)
q) = Pair (m a) -> O Pair m a
forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O (Pair (m a) -> O Pair m a) -> Pair (m a) -> O Pair m a
forall a b. (a -> b) -> a -> b
$ Dimension -> m a -> m a -> m a
forall (m :: * -> *) a.
(Matrix m, AbelianGroup a) =>
Dimension -> m a -> m a -> m a
glue Dimension
d (m a -> m a -> m a) -> Pair (m a) -> Pair (m a -> m a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Pair (m a)
p Pair (m a -> m a) -> Pair (m a) -> Pair (m a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Pair (m a)
q
  split :: forall a.
AbelianGroupZ a =>
Dimension -> Int -> O Pair m a -> (O Pair m a, O Pair m a)
split Dimension
d Int
k (O (m a
x :/: m a
y)) = (Pair (m a) -> O Pair m a
forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O (Pair (m a) -> O Pair m a) -> Pair (m a) -> O Pair m a
forall a b. (a -> b) -> a -> b
$ m a
ax m a -> m a -> Pair (m a)
forall a. a -> a -> Pair a
:/: m a
ay, Pair (m a) -> O Pair m a
forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O (Pair (m a) -> O Pair m a) -> Pair (m a) -> O Pair m a
forall a b. (a -> b) -> a -> b
$ m a
bx m a -> m a -> Pair (m a)
forall a. a -> a -> Pair a
:/: m a
by)
     where (m a
ax,m a
bx) = Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
d Int
k m a
x
           (m a
ay,m a
by) = Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
d Int
k m a
y
  zeroMatrix :: forall a. AbelianGroup a => Int -> Int -> O Pair m a
zeroMatrix Int
x Int
y = Pair (m a) -> O Pair m a
forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O (Pair (m a) -> O Pair m a) -> Pair (m a) -> O Pair m a
forall a b. (a -> b) -> a -> b
$ m a -> Pair (m a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Int -> m a
forall (m :: * -> *) a.
(Matrix m, AbelianGroup a) =>
Int -> Int -> m a
zeroMatrix Int
x Int
y)
  singleton :: forall a. AbelianGroupZ a => a -> O Pair m a
singleton a
x = Pair (m a) -> O Pair m a
forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O (Pair (m a) -> O Pair m a) -> Pair (m a) -> O Pair m a
forall a b. (a -> b) -> a -> b
$ m a -> Pair (m a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> m a
forall (m :: * -> *) a. (Matrix m, AbelianGroupZ a) => a -> m a
singleton a
x) -- Attention: on both sides always!


(<|>) :: (AbelianGroup a, Matrix m) => m a -> m a -> m a
<|> :: forall a (m :: * -> *).
(AbelianGroup a, Matrix m) =>
m a -> m a -> m a
(<|>) = Dimension -> m a -> m a -> m a
forall (m :: * -> *) a.
(Matrix m, AbelianGroup a) =>
Dimension -> m a -> m a -> m a
glue Dimension
XD

(<->) :: (AbelianGroup a, Matrix m)  => m a -> m a -> m a
<-> :: forall a (m :: * -> *).
(AbelianGroup a, Matrix m) =>
m a -> m a -> m a
(<->) = Dimension -> m a -> m a -> m a
forall (m :: * -> *) a.
(Matrix m, AbelianGroup a) =>
Dimension -> m a -> m a -> m a
glue Dimension
YD

countColumns, countRows :: Matrix m => m a -> Int
countColumns :: forall (m :: * -> *) a. Matrix m => m a -> Int
countColumns = Dimension -> Extent -> Int
forall {a}. Dimension -> (a, a) -> a
ext Dimension
XD (Extent -> Int) -> (m a -> Extent) -> m a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> Extent
forall (m :: * -> *) a. Matrix m => m a -> Extent
extent
countRows :: forall (m :: * -> *) a. Matrix m => m a -> Int
countRows = Dimension -> Extent -> Int
forall {a}. Dimension -> (a, a) -> a
ext Dimension
YD (Extent -> Int) -> (m a -> Extent) -> m a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> Extent
forall (m :: * -> *) a. Matrix m => m a -> Extent
extent

chopLastColumn, chopFirstRow, chopFirstColumn, chopLastRow, lastColumn, firstRow :: (AbelianGroupZ a, Matrix m) => m a -> m a
chopFirstRow :: forall a (m :: * -> *). (AbelianGroupZ a, Matrix m) => m a -> m a
chopFirstRow = (m a, m a) -> m a
forall a b. (a, b) -> b
snd ((m a, m a) -> m a) -> (m a -> (m a, m a)) -> m a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
YD Int
1
chopFirstColumn :: forall a (m :: * -> *). (AbelianGroupZ a, Matrix m) => m a -> m a
chopFirstColumn = (m a, m a) -> m a
forall a b. (a, b) -> b
snd ((m a, m a) -> m a) -> (m a -> (m a, m a)) -> m a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
XD Int
1
chopLastColumn :: forall a (m :: * -> *). (AbelianGroupZ a, Matrix m) => m a -> m a
chopLastColumn m a
x = (m a, m a) -> m a
forall a b. (a, b) -> a
fst ((m a, m a) -> m a) -> (m a -> (m a, m a)) -> m a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
XD (m a -> Int
forall (m :: * -> *) a. Matrix m => m a -> Int
countColumns m a
x Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (m a -> m a) -> m a -> m a
forall a b. (a -> b) -> a -> b
$ m a
x
firstRow :: forall a (m :: * -> *). (AbelianGroupZ a, Matrix m) => m a -> m a
firstRow = (m a, m a) -> m a
forall a b. (a, b) -> a
fst ((m a, m a) -> m a) -> (m a -> (m a, m a)) -> m a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
YD Int
1
lastColumn :: forall a (m :: * -> *). (AbelianGroupZ a, Matrix m) => m a -> m a
lastColumn m a
x = (m a, m a) -> m a
forall a b. (a, b) -> b
snd ((m a, m a) -> m a) -> (m a -> (m a, m a)) -> m a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
XD (m a -> Int
forall (m :: * -> *) a. Matrix m => m a -> Int
countColumns m a
x Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (m a -> m a) -> m a -> m a
forall a b. (a -> b) -> a -> b
$ m a
x

chopLastRow :: forall a (m :: * -> *). (AbelianGroupZ a, Matrix m) => m a -> m a
chopLastRow m a
x = (m a, m a) -> m a
forall a b. (a, b) -> a
fst ((m a, m a) -> m a) -> (m a -> (m a, m a)) -> m a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension -> Int -> m a -> (m a, m a)
forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
YD (m a -> Int
forall (m :: * -> *) a. Matrix m => m a -> Int
countRows m a
x Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (m a -> m a) -> m a -> m a
forall a b. (a -> b) -> a -> b
$ m a
x