{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DataKinds #-}
module LAoP.Relation.Internal
(
Relation (..),
Boolean,
Countable,
CountableDimensions,
CountableN,
CountableDimensionsN,
FromListsN,
Liftable,
Trivial,
TrivialP,
empty,
one,
join,
(|||),
fork,
(===),
I.FromNat,
I.Count,
I.Normalize,
I.FromLists,
fromLists,
fromF',
fromF,
toRel,
toLists,
toList,
toBool,
pt,
belongs,
relationBuilder',
relationBuilder,
zeros,
ones,
bang,
point,
conv,
intersection,
union,
sse,
implies,
iff,
ker,
img,
injective,
entire,
simple,
surjective,
representation,
function,
abstraction,
injection,
surjection,
bijection,
domain,
range,
divisionF,
divR,
divL,
divS,
shrunkBy,
overriddenBy,
splitR,
fstR,
sndR,
(><),
eitherR,
i1,
i2,
(-|-),
trans,
untrans,
reflexive,
coreflexive,
transitive,
symmetric,
antiSymmetric,
irreflexive,
connected,
preorder,
partialOrder,
linearOrder,
equivalence,
partialEquivalence,
difunctional,
equalizer,
predR,
guard,
cond,
iden,
comp,
fromF',
fromF,
pointAp,
pointApBool,
pretty,
prettyPrint
)
where
import Data.Void
import qualified LAoP.Matrix.Internal as I
import LAoP.Utils.Internal
import Control.DeepSeq
import Data.Bool
import GHC.TypeLits
import Prelude hiding (id, (.))
type Boolean = Natural 0 1
type Powerset a = List (List a)
newtype Relation a b = R (I.Matrix Boolean (I.Normalize a) (I.Normalize b))
deriving (Show, Eq, Ord, NFData) via (I.Matrix (Natural 1 1) (I.Normalize a) (I.Normalize b))
deriving instance (Read (I.Matrix Boolean (I.Normalize a) (I.Normalize b))) => Read (Relation a b)
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 a b = I.FromLists Boolean (I.Normalize a) (I.Normalize b)
type Liftable a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num Boolean, Ord Boolean)
type Trivial a = 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 Category Relation where
type Object Relation a = (FromListsN a a, CountableN a)
id = iden
(.) = comp
instance Num (Relation a b) where
(R a) + (R b) = R (I.orM a b)
(R a) - (R b) = R (I.subM a b)
(R a) * (R b) = R (I.andM a b)
negate (R a) = R (I.negateM a)
type Zero = Void
type One = ()
empty :: Relation Zero Zero
empty = R I.Empty
one :: Boolean -> Relation One One
one = R . I.One
join :: Relation a c -> Relation b c -> Relation (Either a b) c
join (R a) (R b) = R (I.Join a b)
infixl 3 |||
(|||) ::
Relation a c ->
Relation b c ->
Relation (Either a b) c
(|||) = join
fork :: Relation c a -> Relation c b -> Relation c (Either a b)
fork (R a) (R b) = R (I.Fork a b)
infixl 2 ===
(===) ::
Relation c a ->
Relation c b ->
Relation c (Either a b)
(===) = fork
fromLists :: (FromListsN a b) => [[Boolean]] -> Relation a b
fromLists = R . I.fromLists
relationBuilder' ::
(FromListsN a b, CountableDimensionsN a b) =>
((Int, Int) -> Boolean) -> Relation a b
relationBuilder' = R . I.matrixBuilder'
relationBuilder ::
( FromListsN a b,
Enum a,
Enum b,
Bounded a,
Bounded b,
Eq a,
CountableDimensionsN a b
) => ((a, b) -> Boolean) -> Relation a b
relationBuilder = R . I.matrixBuilder
fromF' ::
( Liftable a b,
CountableDimensionsN c d,
FromListsN d c
)
=> (a -> b) -> Relation c d
fromF' f = R (I.fromFRel' f)
fromF ::
( Liftable a b,
CountableDimensionsN a b,
FromListsN b a
)
=> (a -> b) -> Relation a b
fromF f = R (I.fromFRel f)
toRel ::
( Liftable a b,
CountableDimensionsN a b,
FromListsN b a
)
=> (a -> b -> Bool) -> Relation a b
toRel = R . I.toRel
fromRel ::
( Liftable a b,
Eq a,
CountableDimensionsN a b,
FromListsN a One,
FromListsN b One
)
=> Relation a b -> (a -> b -> Bool)
fromRel r a b = pointApBool a b r
toLists :: Relation a b -> [[Boolean]]
toLists (R m) = I.toLists m
toList :: Relation a b -> [Boolean]
toList (R m) = I.toList m
toBool :: Relation One One -> Bool
toBool r = case toList r of
[Nat 0] -> False
_ -> True
pt ::
( Liftable a b,
Eq a,
CountableDimensionsN a b,
FromListsN a One,
FromListsN b One
)
=> Relation a b -> (a -> List b)
pt r a =
let (L lb) = maxBound
in L [ b | b <- lb, toBool (pointAp a b r) ]
belongs ::
( Bounded a,
Enum a,
Eq a,
CountableDimensionsN (List a) a,
FromListsN a (List a)
)
=> Relation (List a) a
belongs = toRel elemR
where
elemR (L l) x = x `elem` l
zeros ::
(FromListsN a b, CountableDimensionsN a b) =>
Relation a b
zeros = relationBuilder' (const (nat 0))
ones ::
(FromListsN a b, CountableDimensionsN a b) =>
Relation a b
ones = relationBuilder' (const (nat 1))
bang ::
(FromListsN a One, CountableN a) =>
Relation a One
bang = ones
point ::
( Bounded a,
Enum a,
Eq a,
CountableN a,
FromListsN a One
) => a -> Relation One a
point = fromF . const
iden ::
(FromListsN a a, CountableN a) => Relation a a
iden = relationBuilder' (bool (nat 0) (nat 1) . uncurry (==))
comp :: Relation b c -> Relation a b -> Relation a c
comp (R a) (R b) = R (I.compRel a b)
divR :: Relation b c -> Relation b a -> Relation a c
divR (R x) (R y) = R (I.divR x y)
divL :: Relation c b -> Relation a b -> Relation a c
divL (R x) (R y) = R (I.divL x y)
divS :: Relation c a -> Relation b a -> Relation c b
divS (R x) (R y) = R (I.divS x y)
shrunkBy :: Relation b a -> Relation a a -> Relation b a
shrunkBy r s = r `intersection` divR s (conv r)
overriddenBy ::
( FromListsN b b,
CountableN b
) => Relation a b -> Relation a b -> Relation a b
overriddenBy r s = s `union` r `intersection` divR zeros (conv s)
pointAp ::
( Liftable a b,
Eq a,
CountableDimensionsN a b,
FromListsN a One,
FromListsN b One
) => a -> b -> Relation a b -> Relation One One
pointAp a b r = conv (point b) . r . point a
pointApBool ::
( Liftable a b,
Eq a,
CountableDimensionsN a b,
FromListsN a One,
FromListsN b One
) => a -> b -> Relation a b -> Bool
pointApBool a b r = toBool $ conv (point b) . r . point a
conv :: Relation a b -> Relation b a
conv (R a) = R (I.tr a)
sse :: Relation a b -> Relation a b -> Bool
sse a b = a <= b
implies :: Relation a b -> Relation a b -> Relation a b
implies r s = negate r `union` s
iff :: Relation a b -> Relation a b -> Bool
iff r s = r == s
intersection :: Relation a b -> Relation a b -> Relation a b
intersection a b = a * b
union :: Relation a b -> Relation a b -> Relation a b
union a b = a + b
ker :: Relation a b -> Relation a a
ker r = conv r . r
img :: Relation a b -> Relation b b
img r = r . conv r
divisionF :: Relation a c -> Relation b c -> Relation a b
divisionF f g = conv g . f
simple :: (CountableN b, FromListsN b b) => Relation a b -> Bool
simple = coreflexive . img
injective :: (CountableN a, FromListsN a a) => Relation a b -> Bool
injective = coreflexive . ker
entire :: (CountableN a, FromListsN a a) => Relation a b -> Bool
entire = reflexive . ker
surjective :: (CountableN b, FromListsN b b) => Relation a b -> Bool
surjective = reflexive . img
function ::
( CountableDimensionsN a b,
FromListsN a a,
FromListsN b b
)
=> Relation a b -> Bool
function r = simple r && entire r
representation ::
( CountableN a,
FromListsN a a
)
=> Relation a b -> Bool
representation r = injective r && entire r
abstraction ::
( CountableN b,
FromListsN b b
)
=> Relation a b -> Bool
abstraction r = surjective r && simple r
surjection ::
( CountableDimensionsN a b,
FromListsN a a,
FromListsN b b
)
=> Relation a b -> Bool
surjection r = function r && abstraction r
injection ::
( CountableDimensionsN a b,
FromListsN a a,
FromListsN b b
)
=> Relation a b -> Bool
injection r = function r && representation r
bijection ::
( CountableDimensionsN a b,
FromListsN b b,
FromListsN a a
) => Relation a b -> Bool
bijection r = injection r && surjection r
reflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool
reflexive r = id <= r
coreflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool
coreflexive r = r <= id
transitive :: Relation a a -> Bool
transitive r = (r . r) `sse` r
symmetric :: Relation a a -> Bool
symmetric r = r == conv r
antiSymmetric :: (CountableN a, FromListsN a a) => Relation a a -> Bool
antiSymmetric r = (r `intersection` conv r) `sse` id
irreflexive :: (CountableN a, FromListsN a a) => Relation a a -> Bool
irreflexive r = (r `intersection` id) == zeros
connected :: (CountableN a, FromListsN a a) => Relation a a -> Bool
connected r = (r `union` conv r) == ones
preorder :: (CountableN a, FromListsN a a) => Relation a a -> Bool
preorder r = reflexive r && transitive r
partialOrder :: (CountableN a, FromListsN a a) => Relation a a -> Bool
partialOrder r = antiSymmetric r && preorder r
linearOrder :: (CountableN a, FromListsN a a) => Relation a a -> Bool
linearOrder r = connected r && partialOrder r
equivalence :: (CountableN a, FromListsN a a) => Relation a a -> Bool
equivalence r = symmetric r && preorder r
partialEquivalence :: (CountableN a, FromListsN a a) => Relation a a -> Bool
partialEquivalence r = partialOrder r && equivalence r
difunctional :: Relation a b -> Bool
difunctional r = r . conv r . r == r
splitR ::
( CountableDimensionsN a b,
CountableN (a, b),
FromListsN (a, b) a,
FromListsN (a, b) b,
TrivialP a b
)
=> Relation c a -> Relation c b -> Relation c (a, b)
splitR (R f) (R g) = R (I.kr f g)
fstR ::
forall a b .
( CountableDimensionsN a b,
CountableN (a, b),
FromListsN (a, b) a,
TrivialP a b
)
=> Relation (a, b) a
fstR = R (I.fstM @Boolean @(I.Normalize a) @(I.Normalize b))
sndR ::
forall a b .
( CountableDimensionsN a b,
CountableN (a, b),
FromListsN (a, b) b,
TrivialP a b
)
=> Relation (a, b) b
sndR = R (I.sndM @Boolean @(I.Normalize a) @(I.Normalize b))
infixl 4 ><
(><) ::
( CountableDimensionsN a b,
CountableDimensionsN c d,
CountableDimensionsN (a, c) (b, d),
FromListsN (a, c) a,
FromListsN (a, c) c,
FromListsN (b, d) b,
FromListsN (b, d) d,
TrivialP a c,
TrivialP b d
)
=> Relation a b -> Relation c d -> Relation (a, c) (b, d)
(><) (R a) (R b) = R ((I.><) a b)
eitherR :: Relation a c -> Relation b c -> Relation (Either a b) c
eitherR = join
i1 ::
( CountableDimensionsN a b,
FromListsN b a,
FromListsN a a
)
=> Relation a (Either a b)
i1 = R I.i1
i2 ::
( CountableDimensionsN a b,
FromListsN a b,
FromListsN b b
)
=> Relation b (Either a b)
i2 = R I.i2
infixl 5 -|-
(-|-) ::
( CountableDimensionsN b d,
FromListsN b b,
FromListsN d b,
FromListsN b d,
FromListsN d d
)
=> Relation a b -> Relation c d -> Relation (Either a c) (Either b d)
(-|-) (R a) (R b) = R ((I.-|-) a b)
trans ::
( CountableDimensionsN a b,
CountableN c,
CountableDimensionsN (a, b) (c, b),
FromListsN (c, b) c,
FromListsN (c, b) b,
FromListsN (a, b) a,
FromListsN (a, b) b,
Trivial (a, b),
Trivial (c, b),
TrivialP a b,
TrivialP c b
)
=> Relation (a, b) c -> Relation a (c, b)
trans r = splitR r sndR . conv fstR
untrans ::
( CountableDimensionsN a b,
CountableN c,
CountableDimensionsN (a, b) (c, b),
FromListsN (c, b) c,
FromListsN (c, b) b,
FromListsN (a, b) b,
FromListsN (a, b) a,
Trivial (a, b),
Trivial (c, b),
TrivialP a b,
TrivialP c b
)
=> Relation a (c, b) -> Relation (a, b) c
untrans s = fstR . conv (splitR (conv s) sndR)
predR ::
( Bounded a,
Enum a,
CountableN a,
FromListsN a a,
FromListsN Bool a
)
=> Relation a Bool -> Relation a a
predR p = id `intersection` divisionF (fromF (const True)) p
equalizer ::
( CountableN a,
FromListsN a a
)
=> Relation a b -> Relation a b -> Relation a a
equalizer f g = id `intersection` divisionF f g
guard ::
( Bounded b,
Enum b,
CountableN b,
FromListsN b b,
FromListsN Bool b
) => Relation b Bool -> Relation b (Either b b)
guard p = conv (eitherR (predR p) (predR (negate p)))
cond ::
( Bounded b,
Enum b,
CountableN b,
FromListsN b b,
FromListsN Bool b
)
=> Relation b Bool -> Relation b c -> Relation b c -> Relation b c
cond p r s = eitherR r s . guard p
domain ::
( CountableN a,
FromListsN a a
) => Relation a b -> Relation a a
domain r = ker r `intersection` id
range ::
( CountableN b,
FromListsN b b
) => Relation a b -> Relation b b
range r = img r `intersection` id
pretty :: (CountableDimensionsN a b) => Relation a b -> String
pretty (R a) = I.pretty a
prettyPrint :: (CountableDimensionsN a b) => Relation a b -> IO ()
prettyPrint (R a) = I.prettyPrint a