@@ -128,7 +128,17 @@ module Matrix.Internal
128128
129129 -- * Matrix printing
130130 pretty,
131− prettyPrint
131+ prettyPrint,
132+
133+ -- * Other
134+ toBool,
135+ fromBool,
136+ compRel,
137+ fromFRel,
138+ fromFRel',
139+ orM,
140+ andM,
141+ subM
132142 )
133143 where
134144
@@ -245,6 +255,14 @@ instance Num e => Num (Matrix e cols rows) where
245255 signum (Junc a b) = Junc (signum a) (signum b)
246256 signum (Split a b) = Split (signum a) (signum b)
247257
258+instance Ord e => Ord (Matrix e cols rows) where
259+ Empty <= Empty = True
260+ (One a) <= (One b) = a <= b
261+ (Junc a b) <= (Junc c d) = (a <= c) && (b <= d)
262+ (Split a b) <= (Split c d) = (a <= c) && (b <= d)
263+ x@(Split _ _) <= y@(Junc _ _) = x <= abideJS y
264+ x@(Junc _ _) <= y@(Split _ _) = abideJS x <= y
265+
248266-- Primitives
249267
250268-- | Empty matrix constructor
@@ -779,3 +797,121 @@ pretty m = "┌ " ++ unwords (replicate (columns m) blank) ++ " ┐\n" ++
779797-- | Matrix pretty printer
780798prettyPrint :: (KnownNat (Count cols), Show e) => Matrix e cols rows -> IO ()
781799prettyPrint = putStrLn . pretty
800+
801+-- Relational operators functions
802+
803+-- | Helper conversion function
804+toBool :: (Num e, Eq e) => e -> Bool
805+toBool n
806+ | n == 0 = False
807+ | n == 1 = True
808+
809+-- | Helper conversion function
810+fromBool :: Bool -> Natural 0 1
811+fromBool True = nat 1
812+fromBool False = nat 0
813+
814+-- | Relational addition
815+orM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
816+orM Empty Empty = Empty
817+orM (One a) (One b) = One (fromBool (toBool a || toBool b))
818+orM (Junc a b) (Junc c d) = Junc (orM a c) (orM b d)
819+orM (Split a b) (Split c d) = Split (orM a c) (orM b d)
820+orM x@(Split _ _) y@(Junc _ _) = orM x (abideJS y)
821+orM x@(Junc _ _) y@(Split _ _) = orM (abideJS x) y
822+
823+-- | Relational multiplication
824+andM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
825+andM Empty Empty = Empty
826+andM (One a) (One b) = One (fromBool (toBool a && toBool b))
827+andM (Junc a b) (Junc c d) = Junc (andM a c) (andM b d)
828+andM (Split a b) (Split c d) = Split (andM a c) (andM b d)
829+andM x@(Split _ _) y@(Junc _ _) = andM x (abideJS y)
830+andM x@(Junc _ _) y@(Split _ _) = andM (abideJS x) y
831+
832+-- | Relational subtraction
833+subM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
834+subM Empty Empty = Empty
835+subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
836+subM (Junc a b) (Junc c d) = Junc (subM a c) (subM b d)
837+subM (Split a b) (Split c d) = Split (subM a c) (subM b d)
838+subM x@(Split _ _) y@(Junc _ _) = subM x (abideJS y)
839+subM x@(Junc _ _) y@(Split _ _) = subM (abideJS x) y
840+
841+-- | Matrix relational composition.
842+compRel :: Matrix (Natural 0 1) cr rows -> Matrix (Natural 0 1) cols cr -> Matrix (Natural 0 1) cols rows
843+compRel Empty Empty = Empty
844+compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
845+compRel (Junc a b) (Split c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
846+compRel (Split a b) c = Split (compRel a c) (compRel b c) -- Split fusion law
847+compRel c (Junc a b) = Junc (compRel c a) (compRel c b) -- Junc fusion law
848+
849+-- | Lifts functions to relations with arbitrary dimensions.
850+--
851+-- NOTE: Be careful to not ask for a relation bigger than the cardinality of
852+-- types @a@ or @b@ allows.
853+fromFRel ::
854+ forall a b cols rows.
855+ ( Bounded a,
856+ Bounded b,
857+ Enum a,
858+ Enum b,
859+ Eq b,
860+ KnownNat (Count cols),
861+ KnownNat (Count rows),
862+ FromLists (Natural 0 1) rows cols
863+ ) =>
864+ (a -> b) ->
865+ Matrix (Natural 0 1) cols rows
866+fromFRel f =
867+ let minA = minBound @a
868+ maxA = maxBound @a
869+ minB = minBound @b
870+ maxB = maxBound @b
871+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
872+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
873+ elementsA = take ccols [minA .. maxA]
874+ elementsB = take rrows [minB .. maxB]
875+ combinations = (,) <$> elementsA <*> elementsB
876+ combAp = map snd . sort . map (\(a, b) -> if f a == b
877+ then ((fromEnum a, fromEnum b), nat 1)
878+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
879+ mList = buildList combAp rrows
880+ in tr $ fromLists mList
881+ where
882+ buildList [] _ = []
883+ buildList l r = take r l : buildList (drop r l) r
884+
885+-- | Lifts functions to relations with dimensions matching @a@ and @b@
886+-- cardinality's.
887+fromFRel' ::
888+ forall a b.
889+ ( Bounded a,
890+ Bounded b,
891+ Enum a,
892+ Enum b,
893+ Eq b,
894+ KnownNat (Count (Normalize a)),
895+ KnownNat (Count (Normalize b)),
896+ FromLists (Natural 0 1) (Normalize b) (Normalize a)
897+ ) =>
898+ (a -> b) ->
899+ Matrix (Natural 0 1) (Normalize a) (Normalize b)
900+fromFRel' f =
901+ let minA = minBound @a
902+ maxA = maxBound @a
903+ minB = minBound @b
904+ maxB = maxBound @b
905+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
906+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
907+ elementsA = take ccols [minA .. maxA]
908+ elementsB = take rrows [minB .. maxB]
909+ combinations = (,) <$> elementsA <*> elementsB
910+ combAp = map snd . sort . map (\(a, b) -> if f a == b
911+ then ((fromEnum a, fromEnum b), nat 1)
912+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
913+ mList = buildList combAp rrows
914+ in tr $ fromLists mList
915+ where
916+ buildList [] _ = []
917+ buildList l r = take r l : buildList (drop r l) r