{-# 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 forall a. AbelianGroupZ a => a -> Bool
isZero (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
xforall a. Num a => a -> a -> a
-Int
1] ] | Int
j <- [Int
0..Int
yforall a. Num a => a -> a -> a
-Int
1]]
  where x :: Int
x = forall (m :: * -> *) a. Matrix m => m a -> Int
countColumns m a
m
        y :: Int
y = 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
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]
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 forall a (m :: * -> *).
(AbelianGroup a, Matrix m) =>
m a -> m a -> m a
<|> m a
b) forall a (m :: * -> *).
(AbelianGroup a, Matrix m) =>
m a -> m a -> m a
<-> (m a
c 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
x1forall a. AbelianGroup a => a -> a -> a
+a
x2,b
y1)
glueExt Dimension
YD (a
x1,b
y1) (a
x2,b
y2)  = (a
x1,b
y1forall 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
xforall 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
yforall 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)) = forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Int -> Int -> m a -> a
at Int
i Int
j m a
x forall a. AbelianGroup a => a -> 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)) = 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) = forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(Matrix m, AbelianGroup a) =>
Dimension -> m a -> m a -> m a
glue Dimension
d forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Pair (m a)
p 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)) = (forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O forall a b. (a -> b) -> a -> b
$ m a
ax forall a. a -> a -> Pair a
:/: m a
ay, forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O forall a b. (a -> b) -> a -> b
$ m a
bx forall a. a -> a -> Pair a
:/: m a
by)
     where (m a
ax,m a
bx) = 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) = 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 = forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (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 = forall (f :: * -> *) (g :: * -> *) a. f (g a) -> O f g a
O forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (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
(<|>) = 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
(<->) = 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 = forall {a}. Dimension -> (a, a) -> a
ext Dimension
XD forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Matrix m => m a -> Extent
extent
countRows :: forall (m :: * -> *) a. Matrix m => m a -> Int
countRows = forall {a}. Dimension -> (a, a) -> a
ext Dimension
YD forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
XD (forall (m :: * -> *) a. Matrix m => m a -> Int
countColumns m a
x forall a. Num a => a -> a -> a
- Int
1) forall a b. (a -> b) -> a -> b
$ m a
x
firstRow :: forall a (m :: * -> *). (AbelianGroupZ a, Matrix m) => m a -> m a
firstRow = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 = forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
XD (forall (m :: * -> *) a. Matrix m => m a -> Int
countColumns m a
x forall a. Num a => a -> a -> a
- Int
1) 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 = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
(Matrix m, AbelianGroupZ a) =>
Dimension -> Int -> m a -> (m a, m a)
split Dimension
YD (forall (m :: * -> *) a. Matrix m => m a -> Int
countRows m a
x forall a. Num a => a -> a -> a
- Int
1) forall a b. (a -> b) -> a -> b
$ m a
x