{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoStarIsType #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module LAoP.Matrix.Type
(
Matrix (..),
Countable,
CountableDimensions,
CountableN,
CountableDimensionsN,
FromListsN,
Liftable,
Trivial,
TrivialP,
Zero,
One,
empty,
one,
junc,
split,
I.FromNat,
I.Count,
I.Normalize,
I.FromLists,
fromLists,
toLists,
toList,
matrixBuilder,
row,
col,
zeros,
ones,
bang,
point,
constant,
fmapM,
bimapM,
unitM,
multM,
selectM,
returnM,
bindM,
columns,
rows,
tr,
cond,
abideJS,
abideSJ,
zipWithM,
(===),
p1,
p2,
(|||),
i1,
i2,
(-|-),
(><),
kp1,
kp2,
khatri,
identity,
comp,
fromF,
fromF',
toRel,
pretty,
prettyPrint
)
where
import Data.Void
import Data.Proxy
import Data.Kind
import GHC.TypeLits
import Control.DeepSeq
import LAoP.Utils
import qualified Control.Category as C
import qualified LAoP.Matrix.Internal as I
newtype Matrix e (cols :: Type) (rows :: Type) = M (I.Matrix e (I.Normalize cols) (I.Normalize rows))
deriving (Show, Num, Eq, Ord, NFData) via (I.Matrix e (I.Normalize cols) (I.Normalize rows))
type Countable a = KnownNat (I.Count a)
type CountableDimensions a b = (Countable a, Countable b)
type CountableN a = KnownNat (I.Count (I.Normalize a))
type CountableDimensionsN a b = (CountableN a, CountableN b)
type FromListsN e a b = I.FromLists e (I.Normalize a) (I.Normalize b)
type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
type Trivial a = I.Normalize (I.Normalize a) ~ I.Normalize (I.Normalize (I.Normalize a))
type Trivial2 a = I.Normalize a ~ I.Normalize (I.Normalize a)
type Trivial3 a = I.FromNat (I.Count (I.Normalize (I.Normalize a))) ~ I.Normalize (I.Normalize a)
type TrivialP a b = I.Normalize (a, b) ~ I.Normalize (I.Normalize a, I.Normalize b)
instance (Num e) => C.Category (Matrix e) where
id = undefined
(.) = comp
bimapM ::
( Liftable e a b,
Liftable e c d,
CountableDimensionsN a c,
CountableDimensionsN b d,
FromListsN e d c,
FromListsN e b a
) => (a -> b) -> (c -> d) -> Matrix e a c -> Matrix e b d
bimapM f g m = fromF' g `comp` m `comp` tr (fromF' f)
type Zero = Void
type One = ()
empty :: Matrix e Zero Zero
empty = M I.Empty
one :: e -> Matrix e One One
one = M . I.One
junc ::
Matrix e a rows ->
Matrix e b rows ->
Matrix e (Either a b) rows
junc (M a) (M b) = M (I.Junc a b)
infixl 3 |||
(|||) ::
Matrix e a rows ->
Matrix e b rows ->
Matrix e (Either a b) rows
(|||) = junc
split ::
Matrix e cols a ->
Matrix e cols b ->
Matrix e cols (Either a b)
split (M a) (M b) = M (I.Split a b)
infixl 2 ===
(===) ::
Matrix e cols a ->
Matrix e cols b ->
Matrix e cols (Either a b)
(===) = split
fmapM ::
( Liftable e a b,
CountableDimensionsN a b,
FromListsN e b a
)
=>
(a -> b) -> Matrix e c a -> Matrix e c b
fmapM f m = fromF' f `comp` m
unitM :: (Num e) => Matrix e () ()
unitM = one 1
multM ::
( CountableDimensionsN a b,
CountableN (a, b),
Num e,
FromListsN e (a, b) a,
FromListsN e (a, b) b,
TrivialP a b
) => Matrix e c a -> Matrix e c b -> Matrix e c (a, b)
multM = khatri
returnM ::
forall e a .
( Num e,
Enum e,
Enum a,
FromListsN e () a,
Countable a
) => a -> Matrix e One a
returnM a = col l
where
i = fromInteger $ natVal (Proxy :: Proxy (I.Count a))
x = fromEnum a
l = take x [0,0..] ++ [1] ++ take (i - x - 1) [0,0..]
bindM :: (Num e) => Matrix e a b -> Matrix e b c -> Matrix e a c
bindM = flip comp
fromLists :: (FromListsN e cols rows) => [[e]] -> Matrix e cols rows
fromLists = M . I.fromLists
matrixBuilder ::
(FromListsN e cols rows, CountableDimensionsN cols rows )
=> ((Int, Int) -> e) -> Matrix e cols rows
matrixBuilder = M . I.matrixBuilder
col :: (FromListsN e () rows) => [e] -> Matrix e One rows
col = M . I.col
row :: (FromListsN e cols ()) => [e] -> Matrix e cols One
row = M . I.row
fromF ::
( Liftable e a b,
CountableDimensionsN cols rows,
FromListsN e rows cols
) =>
(a -> b) -> Matrix e cols rows
fromF = M . I.fromF
fromF' ::
( Liftable e a b,
CountableDimensionsN a b,
FromListsN e b a
) =>
(a -> b) -> Matrix e a b
fromF' = M . I.fromF'
toRel ::
( Liftable (Natural 0 1) a b,
CountableDimensionsN a b,
FromListsN (Natural 0 1) b a
) => (a -> b -> Bool) -> Matrix (Natural 0 1) a b
toRel = M . I.toRel
toLists :: Matrix e cols rows -> [[e]]
toLists (M m) = I.toLists m
toList :: Matrix e cols rows -> [e]
toList (M m) = I.toList m
zeros ::
(Num e, FromListsN e cols rows, CountableDimensionsN cols rows)
=> Matrix e cols rows
zeros = M I.zeros
ones ::
(Num e, FromListsN e cols rows, CountableDimensionsN cols rows)
=> Matrix e cols rows
ones = M I.ones
constant ::
(Num e, FromListsN e cols rows, CountableDimensionsN cols rows)
=> e -> Matrix e cols rows
constant = M . I.constant
bang ::
forall e cols.
(Num e, Enum e, FromListsN e cols (), CountableN cols) =>
Matrix e cols One
bang = M I.bang
point ::
( Bounded a,
Enum a,
Eq a,
Num e,
Ord e,
CountableN a,
FromListsN e a One
) => a -> Matrix e One a
point = fromF' . const
identity ::
(Num e, FromListsN e a a, CountableN a) =>
Matrix e a a
identity = M I.identity
{-# NOINLINE identity #-}
comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
comp (M a) (M b) = M (I.comp a b)
{-# NOINLINE comp #-}
{-# RULES
"comp/identity1" forall m. comp m identity = m ;
"comp/identity2" forall m. comp identity m = m
#-}
p1 ::
( Num e,
CountableDimensionsN n m,
FromListsN e n m,
FromListsN e m m
) =>
Matrix e (Either m n) m
p1 = M I.p1
p2 ::
( Num e,
CountableDimensionsN n m,
FromListsN e m n,
FromListsN e n n
) =>
Matrix e (Either m n) n
p2 = M I.p2
i1 ::
( Num e,
CountableDimensionsN n m,
FromListsN e n m,
FromListsN e m m
) =>
Matrix e m (Either m n)
i1 = tr p1
i2 ::
( Num e,
CountableDimensionsN n m,
FromListsN e m n,
FromListsN e n n
) =>
Matrix e n (Either m n)
i2 = tr p2
rows :: (CountableN rows) => Matrix e cols rows -> Int
rows (M m) = I.rows m
columns :: (CountableN cols) => Matrix e cols rows -> Int
columns (M m) = I.columns m
infixl 5 -|-
(-|-) ::
( Num e,
CountableDimensionsN j k,
FromListsN e k k,
FromListsN e j k,
FromListsN e k j,
FromListsN e j j
) =>
Matrix e n k ->
Matrix e m j ->
Matrix e (Either n m) (Either k j)
(-|-) (M a) (M b) = M ((I.-|-) a b)
kp1 ::
forall e m k .
( Num e,
CountableDimensionsN m k,
CountableN (m, k),
FromListsN e (m, k) m,
TrivialP m k
) => Matrix e (m, k) m
kp1 = M (I.kp1 @e @(I.Normalize m) @(I.Normalize k))
kp2 ::
forall e m k.
( Num e,
CountableDimensionsN k m,
CountableN (m, k),
FromListsN e (m, k) k,
TrivialP m k
) => Matrix e (m, k) k
kp2 = M (I.kp2 @e @(I.Normalize m) @(I.Normalize k))
khatri ::
forall e cols a b.
( Num e,
CountableDimensionsN a b,
CountableN (a, b),
FromListsN e (a, b) a,
FromListsN e (a, b) b,
TrivialP a b
) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (a, b)
khatri a b =
let kp1' = kp1 @e @a @b
kp2' = kp2 @e @a @b
in comp (tr kp1') a * comp (tr kp2') b
infixl 4 ><
(><) ::
forall e m p n q.
( Num e,
CountableDimensionsN m n,
CountableDimensionsN p q,
CountableDimensionsN (m, n) (p, q),
FromListsN e (m, n) m,
FromListsN e (m, n) n,
FromListsN e (p, q) p,
FromListsN e (p, q) q,
TrivialP m n,
TrivialP p q
) => Matrix e m p -> Matrix e n q -> Matrix e (m, n) (p, q)
(><) a b =
let kp1' = kp1 @e @m @n
kp2' = kp2 @e @m @n
in khatri (comp a kp1') (comp b kp2')
abideJS :: Matrix e cols rows -> Matrix e cols rows
abideJS (M m) = M (I.abideJS m)
abideSJ :: Matrix e cols rows -> Matrix e cols rows
abideSJ (M m) = M (I.abideSJ m)
tr :: Matrix e cols rows -> Matrix e rows cols
tr (M m) = M (I.tr m)
selectM ::
( Num e,
FromListsN e b b,
CountableN b
) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
selectM (M m) (M y) = M (I.select m y)
cond ::
( Trivial a,
Trivial2 a,
Trivial3 a,
CountableN a,
FromListsN e () a,
FromListsN e a (),
FromListsN e a a,
Liftable e a Bool
)
=>
(a -> Bool) -> Matrix e a b -> Matrix e a b -> Matrix e a b
cond p (M a) (M b) = M (I.cond p a b)
pretty :: (CountableDimensionsN cols rows, Show e) => Matrix e cols rows -> String
pretty (M m) = I.pretty m
prettyPrint :: (CountableDimensionsN cols rows, Show e) => Matrix e cols rows -> IO ()
prettyPrint (M m) = I.prettyPrint m
zipWithM :: (e -> f -> g) -> Matrix e a b -> Matrix f a b -> Matrix g a b
zipWithM f (M a) (M b) = M (I.zipWithM f a b)