{-# LANGUAGE StrictData #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoStarIsType #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module LAoP.Matrix.Internal
(
Matrix (..),
empty,
one,
junc,
split,
FromNat,
Count,
Normalize,
FromLists,
fromLists,
toLists,
toList,
matrixBuilder,
row,
col,
zeros,
ones,
bang,
constant,
columns,
rows,
tr,
select,
branch,
cond,
abideJS,
abideSJ,
(===),
p1,
p2,
(|||),
i1,
i2,
(-|-),
(><),
kp1,
kp2,
khatri,
identity,
comp,
fromF,
fromF',
pretty,
prettyPrint,
toBool,
fromBool,
compRel,
divR,
divL,
divS,
fromFRel,
fromFRel',
toRel,
negateM,
orM,
andM,
subM
)
where
import LAoP.Utils.Internal
import Data.Bool
import Data.Kind
import Data.List
import Data.Maybe
import Data.Proxy
import Data.Void
import GHC.TypeLits
import Data.Type.Equality
import GHC.Generics
import Control.DeepSeq
import Control.Category
import Prelude hiding ((.))
data Matrix e cols rows where
Empty :: Matrix e Void Void
One :: e -> Matrix e () ()
Junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
Split :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
deriving instance (Show e) => Show (Matrix e cols rows)
type family Count (d :: Type) :: Nat where
Count (Natural n m) = (m - n) + 1
Count (List a) = (^) 2 (Count a)
Count (Either a b) = (+) (Count a) (Count b)
Count (a, b) = (*) (Count a) (Count b)
Count (a -> b) = (^) (Count b) (Count a)
Count (M1 _ _ f p) = Count (f p)
Count (K1 _ _ _) = 1
Count (V1 _) = 0
Count (U1 _) = 1
Count ((:*:) a b p) = Count (a p) * Count (b p)
Count ((:+:) a b p) = Count (a p) + Count (b p)
Count d = Count (Rep d R)
type family FromNat (n :: Nat) :: Type where
FromNat 0 = Void
FromNat 1 = ()
FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
type family FromNat' (b :: Bool) (m :: Type) :: Type where
FromNat' 'True m = Either m m
FromNat' 'False m = Either () (Either m m)
type family Normalize (d :: Type) :: Type where
Normalize (Either a b) = Either (Normalize a) (Normalize b)
Normalize d = FromNat (Count d)
type Countable a = KnownNat (Count a)
type CountableN a = KnownNat (Count (Normalize a))
type CountableDimensions a b = (Countable a, Countable b)
type CountableDimensionsN a b = (CountableN a, CountableN b)
type FromListsN e a b = FromLists e (Normalize a) (Normalize b)
type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
type Trivial a = FromNat (Count a) ~ a
instance (Num e) => Category (Matrix e) where
id = undefined
(.) = comp
instance NFData e => NFData (Matrix e cols rows) where
rnf Empty = ()
rnf (One e) = rnf e
rnf (Junc a b) = rnf a `seq` rnf b
rnf (Split a b) = rnf a `seq` rnf b
instance Eq e => Eq (Matrix e cols rows) where
Empty == Empty = True
(One a) == (One b) = a == b
(Junc a b) == (Junc c d) = a == c && b == d
(Split a b) == (Split c d) = a == c && b == d
(Split (Junc a b) (Junc c d)) == (Junc (Split a' c') (Split b' d')) =
(a == a') && (b == b') && (c == c') && (d == d')
(Junc (Split a' c') (Split b' d')) == (Split (Junc a b) (Junc c d)) =
(a == a') && (b == b') && (c == c') && (d == d')
instance Num e => Num (Matrix e cols rows) where
Empty + Empty = Empty
(One a) + (One b) = One (a + b)
(Junc a b) + (Junc c d) = Junc (a + c) (b + d)
(Split a b) + (Split c d) = Split (a + c) (b + d)
(Split (Junc a b) (Junc c d)) + (Junc (Split a' c') (Split b' d')) =
Split (Junc (a + a') (b + b')) (Junc (c + c') (d + d'))
(Junc (Split a' c') (Split b' d')) + (Split (Junc a b) (Junc c d)) =
Split (Junc (a + a') (b + b')) (Junc (c + c') (d + d'))
Empty - Empty = Empty
(One a) - (One b) = One (a - b)
(Junc a b) - (Junc c d) = Junc (a - c) (b - d)
(Split a b) - (Split c d) = Split (a - c) (b - d)
(Split (Junc a b) (Junc c d)) - (Junc (Split a' c') (Split b' d')) =
Split (Junc (a - a') (b - b')) (Junc (c - c') (d - d'))
(Junc (Split a' c') (Split b' d')) - (Split (Junc a b) (Junc c d)) =
Split (Junc (a - a') (b - b')) (Junc (c - c') (d - d'))
Empty * Empty = Empty
(One a) * (One b) = One (a * b)
(Junc a b) * (Junc c d) = Junc (a * c) (b * d)
(Split a b) * (Split c d) = Split (a * c) (b * d)
(Split (Junc a b) (Junc c d)) * (Junc (Split a' c') (Split b' d')) =
Split (Junc (a * a') (b * b')) (Junc (c * c') (d * d'))
(Junc (Split a' c') (Split b' d')) * (Split (Junc a b) (Junc c d)) =
Split (Junc (a * a') (b * b')) (Junc (c * c') (d * d'))
abs Empty = Empty
abs (One a) = One (abs a)
abs (Junc a b) = Junc (abs a) (abs b)
abs (Split a b) = Split (abs a) (abs b)
signum Empty = Empty
signum (One a) = One (signum a)
signum (Junc a b) = Junc (signum a) (signum b)
signum (Split a b) = Split (signum a) (signum b)
instance Ord e => Ord (Matrix e cols rows) where
Empty <= Empty = True
(One a) <= (One b) = a <= b
(Junc a b) <= (Junc c d) = (a <= c) && (b <= d)
(Split a b) <= (Split c d) = (a <= c) && (b <= d)
(Split (Junc a b) (Junc c d)) <= (Junc (Split a' c') (Split b' d')) =
(a <= a') && (b <= b') && (c <= c') && (d <= d')
(Junc (Split a' c') (Split b' d')) <= (Split (Junc a b) (Junc c d)) =
(a <= a') && (b <= b') && (c <= c') && (d <= d')
empty :: Matrix e Void Void
empty = Empty
one :: e -> Matrix e () ()
one = One
junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
junc = Junc
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 = Split
infixl 2 ===
(===) :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
(===) = Split
class FromLists e cols rows where
fromLists :: [[e]] -> Matrix e cols rows
instance FromLists e Void Void where
fromLists [] = Empty
fromLists _ = error "Wrong dimensions"
instance {-# OVERLAPPING #-} FromLists e () () where
fromLists [[e]] = One e
fromLists _ = error "Wrong dimensions"
instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
fromLists [h : t] = Junc (One h) (fromLists [t])
fromLists _ = error "Wrong dimensions"
instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), Countable a) => FromLists e (Either a b) () where
fromLists [l] =
let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
in Junc (fromLists [take rowsA l]) (fromLists [drop rowsA l])
fromLists _ = error "Wrong dimensions"
instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
fromLists ([h] : t) = Split (One h) (fromLists t)
fromLists _ = error "Wrong dimensions"
instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) where
fromLists l@([_] : _) =
let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
in Split (fromLists (take rowsA l)) (fromLists (drop rowsA l))
fromLists _ = error "Wrong dimensions"
instance {-# OVERLAPPABLE #-} (FromLists e (Either a b) c, FromLists e (Either a b) d, Countable c) => FromLists e (Either a b) (Either c d) where
fromLists l@(h : t) =
let lh = length h
rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
condition = all (== lh) (map length t)
in if lh > 0 && condition
then Split (fromLists (take rowsC l)) (fromLists (drop rowsC l))
else error "Not all rows have the same length"
matrixBuilder ::
forall e cols rows.
( FromLists e cols rows,
CountableDimensions cols rows
) =>
((Int, Int) -> e) ->
Matrix e cols rows
matrixBuilder f =
let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
r = fromInteger $ natVal (Proxy :: Proxy (Count rows))
positions = [(a, b) | a <- [0 .. (r - 1)], b <- [0 .. (c - 1)]]
in fromLists . map (map f) . groupBy (\(x, _) (w, _) -> x == w) $ positions
col :: (FromLists e () rows) => [e] -> Matrix e () rows
col = fromLists . map (: [])
row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
row = fromLists . (: [])
fromF ::
forall a b cols rows e.
( Liftable e a b,
CountableDimensions cols rows,
FromLists e rows cols
) =>
(a -> b) ->
Matrix e cols rows
fromF f =
let minA = minBound @a
maxA = maxBound @a
minB = minBound @b
maxB = maxBound @b
ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
elementsA = take ccols [minA .. maxA]
elementsB = take rrows [minB .. maxB]
combinations = (,) <$> elementsA <*> elementsB
combAp = map snd . sort . map (\(a, b) -> if f a == b
then ((fromEnum a, fromEnum b), 1)
else ((fromEnum a, fromEnum b), 0)) $ combinations
mList = buildList combAp rrows
in tr $ fromLists mList
where
buildList [] _ = []
buildList l r = take r l : buildList (drop r l) r
fromF' ::
forall a b e.
( Liftable e a b,
CountableDimensionsN a b,
FromListsN e b a
) =>
(a -> b) ->
Matrix e (Normalize a) (Normalize b)
fromF' f =
let minA = minBound @a
maxA = maxBound @a
minB = minBound @b
maxB = maxBound @b
ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
elementsA = take ccols [minA .. maxA]
elementsB = take rrows [minB .. maxB]
combinations = (,) <$> elementsA <*> elementsB
combAp = map snd . sort . map (\(a, b) -> if f a == b
then ((fromEnum a, fromEnum b), 1)
else ((fromEnum a, fromEnum b), 0)) $ combinations
mList = buildList combAp rrows
in tr $ fromLists mList
where
buildList [] _ = []
buildList l r = take r l : buildList (drop r l) r
toLists :: Matrix e cols rows -> [[e]]
toLists Empty = []
toLists (One e) = [[e]]
toLists (Split l r) = toLists l ++ toLists r
toLists (Junc l r) = zipWith (++) (toLists l) (toLists r)
toList :: Matrix e cols rows -> [e]
toList = concat . toLists
zeros :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
zeros = matrixBuilder (const 0)
ones :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
ones = matrixBuilder (const 1)
constant :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => e -> Matrix e cols rows
constant e = matrixBuilder (const e)
bang :: forall e cols. (Num e, Enum e, FromLists e cols (), Countable cols) => Matrix e cols ()
bang =
let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
in fromLists [take c [1, 1 ..]]
identity :: (Num e, FromLists e cols cols, Countable cols) => Matrix e cols cols
identity = matrixBuilder (bool 0 1 . uncurry (==))
{-# NOINLINE identity #-}
comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
comp Empty Empty = Empty
comp (One a) (One b) = One (a * b)
comp (Junc a b) (Split c d) = comp a c + comp b d
comp (Split a b) c = Split (comp a c) (comp b c)
comp c (Junc a b) = Junc (comp c a) (comp c b)
{-# NOINLINE comp #-}
{-# RULES
"comp/identity1" forall m. comp m identity = m ;
"comp/identity2" forall m. comp identity m = m
#-}
p1 :: forall e m n. (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e (Either m n) m
p1 =
let iden = identity :: Matrix e m m
zero = zeros :: Matrix e n m
in junc iden zero
p2 :: forall e m n. (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e (Either m n) n
p2 =
let iden = identity :: Matrix e n n
zero = zeros :: Matrix e m n
in junc zero iden
i1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e m (Either m n)
i1 = tr p1
i2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e n (Either m n)
i2 = tr p2
rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
infixl 5 -|-
(-|-) ::
forall e n k m j.
( Num e,
CountableDimensions j k,
FromLists e k k,
FromLists e j k,
FromLists e k j,
FromLists e j j
) =>
Matrix e n k ->
Matrix e m j ->
Matrix e (Either n m) (Either k j)
(-|-) a b = Junc (i1 . a) (i2 . b)
kp1 ::
forall e m k .
( Num e,
CountableDimensions k m,
FromLists e (Normalize (m, k)) m,
CountableN (m, k)
) => Matrix e (Normalize (m, k)) m
kp1 = matrixBuilder f
where
offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
f (x, y)
| y >= (x * offset) && y <= (x * offset + offset - 1) = 1
| otherwise = 0
kp2 ::
forall e m k .
( Num e,
CountableDimensions k m,
FromLists e (Normalize (m, k)) k,
CountableN (m, k)
) => Matrix e (Normalize (m, k)) k
kp2 = matrixBuilder f
where
offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
f (x, y)
| x == y || mod (y - x) offset == 0 = 1
| otherwise = 0
khatri ::
forall e cols a b.
( Num e,
CountableDimensions a b,
CountableN (a, b),
FromLists e (Normalize (a, b)) a,
FromLists e (Normalize (a, b)) b
) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
khatri a b =
let kp1' = kp1 @e @a @b
kp2' = kp2 @e @a @b
in (tr kp1') . a * (tr kp2') . b
infixl 4 ><
(><) ::
forall e m p n q.
( Num e,
CountableDimensions m n,
CountableDimensions p q,
CountableDimensionsN (m, n) (p, q),
FromLists e (Normalize (m, n)) m,
FromLists e (Normalize (m, n)) n,
FromLists e (Normalize (p, q)) p,
FromLists e (Normalize (p, q)) q
)
=> Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
(><) a b =
let kp1' = kp1 @e @m @n
kp2' = kp2 @e @m @n
in khatri (a . kp1') (b . kp2')
abideJS :: Matrix e cols rows -> Matrix e cols rows
abideJS (Junc (Split a c) (Split b d)) = Split (Junc (abideJS a) (abideJS b)) (Junc (abideJS c) (abideJS d))
abideJS Empty = Empty
abideJS (One e) = One e
abideJS (Junc a b) = Junc (abideJS a) (abideJS b)
abideJS (Split a b) = Split (abideJS a) (abideJS b)
abideSJ :: Matrix e cols rows -> Matrix e cols rows
abideSJ (Split (Junc a b) (Junc c d)) = Junc (Split (abideSJ a) (abideSJ c)) (Split (abideSJ b) (abideSJ d))
abideSJ Empty = Empty
abideSJ (One e) = One e
abideSJ (Junc a b) = Junc (abideSJ a) (abideSJ b)
abideSJ (Split a b) = Split (abideSJ a) (abideSJ b)
tr :: Matrix e cols rows -> Matrix e rows cols
tr Empty = Empty
tr (One e) = One e
tr (Junc a b) = Split (tr a) (tr b)
tr (Split a b) = Junc (tr a) (tr b)
select :: (Num e, FromLists e b b, Countable b) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
select (Split a b) y = y . a + b
select (Junc (Split a c) (Split b d)) y = junc (y . a + c) (y . b + d)
select m y = junc y identity . m
branch ::
( Num e,
CountableDimensions a b,
CountableDimensions c (Either b c),
FromLists e c b,
FromLists e a b,
FromLists e a a,
FromLists e b b,
FromLists e c c,
FromLists e b a,
FromLists e b c,
FromLists e (Either b c) b,
FromLists e (Either b c) c
)
=> Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
branch x l r = f x `select` g l `select` r
where
f :: (Num e, Countable a, CountableDimensions b c, FromLists e a b, FromLists e c b, FromLists e b b, FromLists e b a, FromLists e a a)
=> Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
f m = split (tr i1) (i1 . tr i2) . m
g :: (Num e, CountableDimensions b c, FromLists e b c, FromLists e c c) => Matrix e a c -> Matrix e a (Either b c)
g m = i2 . m
cond ::
( Trivial cols,
Countable cols,
FromLists e () cols,
FromLists e cols (),
FromLists e cols cols,
Bounded a,
Enum a,
Num e,
Ord e
)
=>
(a -> Bool) -> Matrix e cols rows -> Matrix e cols rows -> Matrix e cols rows
cond p f g = junc f g . grd p
grd ::
( Trivial q,
Countable q,
FromLists e () q,
FromLists e q (),
FromLists e q q,
Bounded a,
Enum a,
Num e,
Ord e
)
=>
(a -> Bool) -> Matrix e q (Either q q)
grd f = split (corr f) (corr (not . f))
corr ::
forall e a q .
( Trivial q,
Countable q,
FromLists e () q,
FromLists e q (),
FromLists e q q,
Liftable e a Bool
)
=> (a -> Bool) -> Matrix e q q
corr p = let f = fromF p :: Matrix e q ()
in khatri f (identity :: Matrix e q q)
prettyAux :: Show e => [[e]] -> [[e]] -> String
prettyAux [] _ = ""
prettyAux [[e]] m = "│ " ++ fill (show e) ++ " │\n"
where
v = fmap show m
widest = maximum $ fmap length v
fill str = replicate (widest - length str - 2) ' ' ++ str
prettyAux [h] m = "│ " ++ fill (unwords $ map show h) ++ " │\n"
where
v = fmap show m
widest = maximum $ fmap length v
fill str = replicate (widest - length str - 2) ' ' ++ str
prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
prettyAux t l
where
v = fmap show l
widest = maximum $ fmap length v
fill str = replicate (widest - length str - 2) ' ' ++ str
pretty :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> String
pretty m = concat
[ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
, unlines
[ "│ " ++ unwords (fmap (\j -> fill $ show $ getElem i j m) [1..columns m]) ++ " │" | i <- [1..rows m] ]
, "└ ", unwords (replicate (columns m) blank), " ┘"
]
where
strings = map show (toList m)
widest = maximum $ map length strings
fill str = replicate (widest - length str) ' ' ++ str
blank = fill ""
safeGet i j m
| i > rows m || j > columns m || i < 1 || j < 1 = Nothing
| otherwise = Just $ unsafeGet i j m (toList m)
unsafeGet i j m l = l !! encode (columns m) (i,j)
encode m (i,j) = (i-1)*m + j - 1
getElem i j m =
fromMaybe
(error $
"getElem: Trying to get the "
++ show (i, j)
++ " element from a "
++ show (rows m) ++ "x" ++ show (columns m)
++ " matrix."
)
(safeGet i j m)
prettyPrint :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> IO ()
prettyPrint = putStrLn . pretty
type Boolean = Natural 0 1
type Relation a b = Matrix Boolean a b
toBool :: (Num e, Eq e) => e -> Bool
toBool n
| n == 0 = False
| n == 1 = True
fromBool :: Bool -> Natural 0 1
fromBool True = nat 1
fromBool False = nat 0
negateM :: Relation cols rows -> Relation cols rows
negateM Empty = Empty
negateM (One (Nat 0)) = One (Nat 1)
negateM (One (Nat 1)) = One (Nat 0)
negateM (Junc a b) = Junc (negateM a) (negateM b)
negateM (Split a b) = Split (negateM a) (negateM b)
orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
orM Empty Empty = Empty
orM (One a) (One b) = One (fromBool (toBool a || toBool b))
orM (Junc a b) (Junc c d) = Junc (orM a c) (orM b d)
orM (Split a b) (Split c d) = Split (orM a c) (orM b d)
orM x@(Split _ _) y@(Junc _ _) = orM x (abideJS y)
orM x@(Junc _ _) y@(Split _ _) = orM (abideJS x) y
andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
andM Empty Empty = Empty
andM (One a) (One b) = One (fromBool (toBool a && toBool b))
andM (Junc a b) (Junc c d) = Junc (andM a c) (andM b d)
andM (Split a b) (Split c d) = Split (andM a c) (andM b d)
andM x@(Split _ _) y@(Junc _ _) = andM x (abideJS y)
andM x@(Junc _ _) y@(Split _ _) = andM (abideJS x) y
subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
subM Empty Empty = Empty
subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
subM (Junc a b) (Junc c d) = Junc (subM a c) (subM b d)
subM (Split a b) (Split c d) = Split (subM a c) (subM b d)
subM x@(Split _ _) y@(Junc _ _) = subM x (abideJS y)
subM x@(Junc _ _) y@(Split _ _) = subM (abideJS x) y
compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
compRel Empty Empty = Empty
compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
compRel (Junc a b) (Split c d) = orM (compRel a c) (compRel b d)
compRel (Split a b) c = Split (compRel a c) (compRel b c)
compRel c (Junc a b) = Junc (compRel c a) (compRel c b)
divR :: Relation b c -> Relation b a -> Relation a c
divR Empty Empty = Empty
divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a))
divR (Junc a b) (Junc c d) = andM (divR a c) (divR b d)
divR (Split a b) c = Split (divR a c) (divR b c)
divR c (Split a b) = Junc (divR c a) (divR c b)
divL :: Relation c b -> Relation a b -> Relation a c
divL x y = tr (divR (tr y) (tr x))
divS :: Relation c a -> Relation b a -> Relation c b
divS s r = divL r s `intersection` divR (tr r) (tr s)
where
intersection = andM
fromFRel ::
forall a b cols rows.
( Liftable Boolean a b,
CountableDimensions cols rows,
FromLists Boolean rows cols
) =>
(a -> b) ->
Relation cols rows
fromFRel f =
let minA = minBound @a
maxA = maxBound @a
minB = minBound @b
maxB = maxBound @b
ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
elementsA = take ccols [minA .. maxA]
elementsB = take rrows [minB .. maxB]
combinations = (,) <$> elementsA <*> elementsB
combAp = map snd . sort . map (\(a, b) -> if f a == b
then ((fromEnum a, fromEnum b), nat 1)
else ((fromEnum a, fromEnum b), nat 0)) $ combinations
mList = buildList combAp rrows
in tr $ fromLists mList
where
buildList [] _ = []
buildList l r = take r l : buildList (drop r l) r
fromFRel' ::
forall a b.
( Liftable Boolean a b,
CountableDimensionsN a b,
FromLists Boolean (Normalize b) (Normalize a)
) =>
(a -> b) ->
Relation (Normalize a) (Normalize b)
fromFRel' f =
let minA = minBound @a
maxA = maxBound @a
minB = minBound @b
maxB = maxBound @b
ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
elementsA = take ccols [minA .. maxA]
elementsB = take rrows [minB .. maxB]
combinations = (,) <$> elementsA <*> elementsB
combAp = map snd . sort . map (\(a, b) -> if f a == b
then ((fromEnum a, fromEnum b), nat 1)
else ((fromEnum a, fromEnum b), nat 0)) $ combinations
mList = buildList combAp rrows
in tr $ fromLists mList
where
buildList [] _ = []
buildList l r = take r l : buildList (drop r l) r
toRel ::
forall a b.
( Bounded a,
Bounded b,
Enum a,
Enum b,
Eq b,
CountableDimensionsN a b,
FromListsN Boolean b a
)
=> (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
toRel f =
let minA = minBound @a
maxA = maxBound @a
minB = minBound @b
maxB = maxBound @b
ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
elementsA = take ccols [minA .. maxA]
elementsB = take rrows [minB .. maxB]
combinations = (,) <$> elementsA <*> elementsB
combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
then ((fromEnum a, fromEnum b), nat 1)
else ((fromEnum a, fromEnum b), nat 0)) $ combinations
mList = buildList combAp rrows
in tr $ fromLists mList
where
buildList [] _ = []
buildList l r = take r l : buildList (drop r l) r