{-# 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,
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.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 (Powerset a) = (^) (Count a) (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 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)
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
x@(Split _ _) == y@(Junc _ _) = x == abideJS y
x@(Junc _ _) == y@(Split _ _) = abideJS x == y
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)
x@(Split _ _) + y@(Junc _ _) = x + abideJS y
x@(Junc _ _) + y@(Split _ _) = abideJS x + y
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)
x@(Split _ _) - y@(Junc _ _) = x - abideJS y
x@(Junc _ _) - y@(Split _ _) = abideJS x - y
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)
x@(Split _ _) * y@(Junc _ _) = x * abideJS y
x@(Junc _ _) * y@(Split _ _) = abideJS x * y
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)
x@(Split _ _) <= y@(Junc _ _) = x <= abideJS y
x@(Junc _ _) <= y@(Split _ _) = abideJS x <= y
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 (==))
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)
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 m y = junc y identity . m
cond ::
( cols ~ Normalize 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 ::
( q ~ Normalize 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 .
( q ~ Normalize 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 :: (Countable cols, Show e) => Matrix e cols rows -> String
pretty m = "┌ " ++ unwords (replicate (columns m) blank) ++ " ┐\n" ++
prettyAux (toLists m) (toLists m) ++
"└ " ++ unwords (replicate (columns m) blank) ++ " ┘"
where
v = fmap show (toList m)
widest = maximum $ fmap length v
fill str = replicate (widest - length str) ' ' ++ str
blank = fill ""
prettyPrint :: (Countable cols, 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