@@ -30,7 +30,7 @@
3030-- motivation behind the library, the underlying theory, and implementation details.
3131--
3232-- This module offers many of the combinators mentioned in the work of
33−-- Macedo (2012) and Oliveira (2012).
33+-- Macedo (2012) and Oliveira (2012).
3434--
3535-- This is an Internal module and it is no supposed to be imported.
3636--
@@ -43,8 +43,8 @@ module LAoP.Matrix.Internal
4343 --
4444 -- There exists two type families that make it easier to write
4545 -- matrix dimensions: 'FromNat' and 'Count'. This approach
46− -- leads to a very straightforward implementation
47− -- of LAoP combinators.
46+ -- leads to a very straightforward implementation
47+ -- of LAoP combinators.
4848
4949 -- * Type safe matrix representation
5050 Matrix (..),
@@ -60,6 +60,7 @@ module LAoP.Matrix.Internal
6060 Trivial,
6161
6262 -- * Primitives
63+ empty,
6364 one,
6465 join,
6566 fork,
@@ -86,9 +87,7 @@ module LAoP.Matrix.Internal
8687 -- * Misc
8788 -- ** Get dimensions
8889 columns,
89− columns',
9090 rows,
91− rows',
9291
9392 -- ** Matrix Transposition
9493 tr,
@@ -176,7 +175,6 @@ import Data.Kind
176175import Data.List
177176import Data.Maybe
178177import Data.Proxy
179−import Data.Typeable
180178import Data.Void
181179import GHC.TypeLits
182180import Data.Type.Equality
@@ -187,6 +185,7 @@ import qualified Prelude (id, (.))
187185
188186-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
189187data Matrix e cols rows where
188+ Empty :: Matrix e Void Void
190189 One :: e -> Matrix e () ()
191190 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
192191 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
@@ -216,6 +215,7 @@ type family Count (d :: Type) :: Nat where
216215--
217216-- Thanks to Li-Yao Xia this type family is super fast.
218217type family FromNat (n :: Nat) :: Type where
218+ FromNat 0 = Void
219219 FromNat 1 = ()
220220 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
221221
@@ -243,15 +243,17 @@ type Trivial a = FromNat (Count a) ~ a
243243-- class.
244244instance (Num e) => Category (Matrix e) where
245245 type Object (Matrix e) a = (FL a a, Countable a)
246− id = iden
246+ id = iden
247247 (.) = comp
248248
249249instance NFData e => NFData (Matrix e cols rows) where
250+ rnf Empty = ()
250251 rnf (One e) = rnf e
251252 rnf (Join a b) = rnf a `seq` rnf b
252253 rnf (Fork a b) = rnf a `seq` rnf b
253254
254255instance Eq e => Eq (Matrix e cols rows) where
256+ Empty == Empty = True
255257 (One a) == (One b) = a == b
256258 (Join a b) == (Join c d) = a == c && b == d
257259 (Fork a b) == (Fork c d) = a == c && b == d
@@ -259,21 +261,25 @@ instance Eq e => Eq (Matrix e cols rows) where
259261 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
260262
261263instance Num e => Num (Matrix e cols rows) where
264+
262265 a + b = zipWithM (+) a b
263266
264267 a - b = zipWithM (-) a b
265268
266269 a * b = zipWithM (*) a b
267270
271+ abs Empty = Empty
268272 abs (One a) = One (abs a)
269273 abs (Join a b) = Join (abs a) (abs b)
270274 abs (Fork a b) = Fork (abs a) (abs b)
271275
276+ signum Empty = Empty
272277 signum (One a) = One (signum a)
273278 signum (Join a b) = Join (signum a) (signum b)
274279 signum (Fork a b) = Fork (signum a) (signum b)
275280
276281instance Ord e => Ord (Matrix e cols rows) where
282+ Empty <= Empty = True
277283 (One a) <= (One b) = a <= b
278284 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
279285 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
@@ -282,6 +288,10 @@ instance Ord e => Ord (Matrix e cols rows) where
282288
283289-- Primitives
284290
291+-- | Empty matrix constructor
292+empty :: Matrix e Void Void
293+empty = Empty
294+
285295-- | Unit matrix constructor
286296one :: e -> Matrix e () ()
287297one = One
@@ -317,34 +327,35 @@ class FromLists cols rows where
317327 -- error if the dimensions do not match.
318328 fromLists :: [[e]] -> Matrix e cols rows
319329
320−instance FromLists () () where
330+instance FromLists Void Void where
331+ fromLists [] = Empty
332+ fromLists _ = error "Wrong dimensions"
333+
334+instance {-# OVERLAPPING #-} FromLists () () where
321335 fromLists [[e]] = One e
322336 fromLists _ = error "Wrong dimensions"
323337
324−instance (FromLists cols ()) => FromLists (Either () cols) () where
338+instance {-# OVERLAPPING #-} (FromLists cols ()) => FromLists (Either () cols) () where
325339 fromLists [h : t] = Join (One h) (fromLists [t])
326340 fromLists _ = error "Wrong dimensions"
327341
328−instance {-# OVERLAPPABLE #-}
329− (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
342+instance {-# OVERLAPPABLE #-} (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
330343 fromLists [l] =
331344 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
332345 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
333346 fromLists _ = error "Wrong dimensions"
334347
335−instance (FromLists () rows) => FromLists () (Either () rows) where
348+instance {-# OVERLAPPING #-} (FromLists () rows) => FromLists () (Either () rows) where
336349 fromLists ([h] : t) = Fork (One h) (fromLists t)
337350 fromLists _ = error "Wrong dimensions"
338351
339−instance {-# OVERLAPPABLE #-}
340− (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
341− fromLists l@([_] : _) =
352+instance {-# OVERLAPPABLE #-} (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
353+ fromLists l@([_] : _) =
342354 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
343355 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
344356 fromLists _ = error "Wrong dimensions"
345357
346−instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
347− => FromLists (Either a b) (Either c d) where
358+instance {-# OVERLAPPABLE #-} (FromLists (Either a b) c, FromLists (Either a b) d, Countable c) => FromLists (Either a b) (Either c d) where
348359 fromLists l@(h : t) =
349360 let lh = length h
350361 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
@@ -371,15 +382,16 @@ matrixBuilder' f =
371382matrixBuilder ::
372383 forall e a b.
373384 ( FLN a b,
385+ CountableN b,
374386 Enum a,
375387 Enum b,
376388 Bounded a,
377389 Bounded b,
378390 Eq a,
379− Countable b
391+ CountableDimsN a b
380392 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
381393matrixBuilder f =
382− let r = fromInteger $ natVal (Proxy :: Proxy (Count b))
394+ let r = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
383395 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
384396 in fromLists . map (map f) . transpose . buildList r $ positions
385397 where
@@ -435,12 +447,30 @@ fromF ::
435447 ) =>
436448 (a -> b) ->
437449 Matrix e (Normalize a) (Normalize b)
438−fromF = fromF'
450+fromF f =
451+ let minA = minBound @a
452+ maxA = maxBound @a
453+ minB = minBound @b
454+ maxB = maxBound @b
455+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
456+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
457+ elementsA = take ccols [minA .. maxA]
458+ elementsB = take rrows [minB .. maxB]
459+ combinations = (,) <$> elementsA <*> elementsB
460+ combAp = map snd . sort . map (\(a, b) -> if f a == b
461+ then ((fromEnum a, fromEnum b), 1)
462+ else ((fromEnum a, fromEnum b), 0)) $ combinations
463+ mList = buildList combAp rrows
464+ in tr $ fromLists mList
465+ where
466+ buildList [] _ = []
467+ buildList l r = take r l : buildList (drop r l) r
439468
440469-- Conversion
441470
442471-- | Converts a matrix to a list of lists of elements.
443472toLists :: Matrix e cols rows -> [[e]]
473+toLists Empty = []
444474toLists (One e) = [[e]]
445475toLists (Fork l r) = toLists l ++ toLists r
446476toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
@@ -492,12 +522,13 @@ iden = matrixBuilder' (bool 0 1 . uncurry (==))
492522-- This definition takes advantage of divide-and-conquer and fusion laws
493523-- from LAoP.
494524comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
525+comp Empty Empty = Empty
495526comp (One a) (One b) = One (a * b)
496527comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
497528comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
498529comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
499530{-# NOINLINE comp #-}
500−{-# RULES
531+{-# RULES
501532 "comp/iden1" forall m. comp m iden = m ;
502533 "comp/iden2" forall m. comp iden m = m
503534#-}
@@ -507,6 +538,7 @@ comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
507538infixl 7 .|
508539-- | Scalar multiplication of matrices.
509540(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
541+(.|) _ Empty = Empty
510542(.|) e (One a) = One (e * a)
511543(.|) e (Join a b) = Join (e .| a) (e .| b)
512544(.|) e (Fork a b) = Fork (e .| a) (e .| b)
@@ -516,6 +548,7 @@ infixl 7 .|
516548infixl 7 ./
517549-- | Scalar multiplication of matrices.
518550(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
551+(./) Empty _ = Empty
519552(./) (One a) e = One (a / e)
520553(./) (Join a b) e = Join (a ./ e) (b ./ e)
521554(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
@@ -544,38 +577,24 @@ i2 = tr p2
544577
545578-- | Obtain the number of rows.
546579--
547−-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
548−-- dimensions in constant time. For a version that doesn't require the
549−-- constraint see 'rows''.
580+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
581+-- dimensions in constant time.
582+--
583+-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
584+-- exchange for performance.
550585rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
551586rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
552587
553−-- | Obtain the number of rows in an inefficient manner, but without any
554−-- constraints.
555−--
556−-- For a more efficient version see 'rows'.
557−rows' :: Matrix e cols rows -> Int
558−rows' (One _) = 1
559−rows' (Join lhs _) = rows' lhs
560−rows' (Fork top bottom) = rows' top + rows' bottom
561−
562588-- | Obtain the number of columns.
589+--
590+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
591+-- dimensions in constant time.
563592--
564−-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
565−-- dimensions in constant time. For a version that doesn't require the
566−-- constraint see 'columns''.
593+-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
594+-- exchange for performance.
567595columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
568596columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
569597
570−-- | Obtain the number of columns in an inefficient manner, but without any
571−-- constraints.
572−--
573−-- For a more efficient version see 'columns'.
574−columns' :: Matrix e cols rows -> Int
575−columns' (One _) = 1
576−columns' (Join lhs rhs) = columns' lhs + columns' rhs
577−columns' (Fork top _) = columns' top
578−
579598-- Coproduct Bifunctor
580599
581600infixl 5 -|-
@@ -630,7 +649,7 @@ sndM = matrixBuilder' f
630649-- | Khatri Rao Matrix product also known as matrix pairing.
631650--
632651-- NOTE: That this is not a true categorical product, see for instance:
633−--
652+--
634653-- @
635654-- | fstM . kr a b == a
636655-- kr a b ==> |
@@ -666,7 +685,7 @@ infixl 4 ><
666685 FL (Normalize (m, n)) n,
667686 FL (Normalize (p, q)) p,
668687 FL (Normalize (p, q)) q
669− )
688+ )
670689 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
671690(><) a b =
672691 let fstM' = fstM @e @m @n
@@ -684,6 +703,7 @@ infixl 4 ><
684703-- @
685704abideJF :: Matrix e cols rows -> Matrix e cols rows
686705abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
706+abideJF Empty = Empty
687707abideJF (One e) = One e
688708abideJF (Join a b) = Join (abideJF a) (abideJF b)
689709abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
@@ -697,6 +717,7 @@ abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
697717-- @
698718abideFJ :: Matrix e cols rows -> Matrix e cols rows
699719abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
720+abideFJ Empty = Empty
700721abideFJ (One e) = One e
701722abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
702723abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
@@ -705,6 +726,7 @@ abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
705726
706727-- | Matrix transposition.
707728tr :: Matrix e cols rows -> Matrix e rows cols
729+tr Empty = Empty
708730tr (One e) = One e
709731tr (Join a b) = Fork (tr a) (tr b)
710732tr (Fork a b) = Join (tr a) (tr b)
@@ -843,6 +865,7 @@ prettyPrint = putStrLn . pretty
843865
844866-- | Zip two matrices with a given binary function
845867zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
868+zipWithM _ Empty Empty = Empty
846869zipWithM f (One a) (One b) = One (f a b)
847870zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
848871zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
@@ -867,12 +890,14 @@ fromBool False = nat 0
867890
868891-- | Relational negation
869892negateM :: Relation cols rows -> Relation cols rows
893+negateM Empty = Empty
870894negateM (One (Nat p)) = One (Nat (negate p))
871895negateM (Join a b) = Join (negateM a) (negateM b)
872896negateM (Fork a b) = Fork (negateM a) (negateM b)
873897
874898-- | Relational addition
875899orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
900+orM Empty Empty = Empty
876901orM (One a) (One b) = One (fromBool (toBool a || toBool b))
877902orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
878903orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
@@ -881,6 +906,7 @@ orM x@(Join _ _) y@(Fork _ _) = orM (abideJF x) y
881906
882907-- | Relational multiplication
883908andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
909+andM Empty Empty = Empty
884910andM (One a) (One b) = One (fromBool (toBool a && toBool b))
885911andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
886912andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
@@ -889,6 +915,7 @@ andM x@(Join _ _) y@(Fork _ _) = andM (abideJF x) y
889915
890916-- | Relational subtraction
891917subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
918+subM Empty Empty = Empty
892919subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
893920subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
894921subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
@@ -897,6 +924,7 @@ subM x@(Join _ _) y@(Fork _ _) = subM (abideJF x) y
897924
898925-- | Matrix relational composition.
899926compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
927+compRel Empty Empty = Empty
900928compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
901929compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
902930compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
@@ -904,6 +932,7 @@ compRel c (Join a b) = Join (compRel c a) (compRel c b) -- Join fusion
904932
905933-- | Matrix relational right division
906934divR :: Relation b c -> Relation b a -> Relation a c
935+divR Empty Empty = Empty
907936divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
908937divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
909938divR (Fork a b) c = Fork (divR a c) (divR b c)
@@ -931,7 +960,24 @@ fromFRel' ::
931960 ) =>
932961 (a -> b) ->
933962 Relation cols rows
934−fromFRel' = fromF'
963+fromFRel' f =
964+ let minA = minBound @a
965+ maxA = maxBound @a
966+ minB = minBound @b
967+ maxB = maxBound @b
968+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
969+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
970+ elementsA = take ccols [minA .. maxA]
971+ elementsB = take rrows [minB .. maxB]
972+ combinations = (,) <$> elementsA <*> elementsB
973+ combAp = map snd . sort . map (\(a, b) -> if f a == b
974+ then ((fromEnum a, fromEnum b), nat 1)
975+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
976+ mList = buildList combAp rrows
977+ in tr $ fromLists mList
978+ where
979+ buildList [] _ = []
980+ buildList l r = take r l : buildList (drop r l) r
935981
936982-- | Lifts functions to relations with dimensions matching @a@ and @b@
937983-- cardinality's.
@@ -939,11 +985,28 @@ fromFRel ::
939985 forall a b.
940986 ( Liftable Boolean a b,
941987 CountableDimsN a b,
942− FLN b a
988+ FL (Normalize b) (Normalize a)
943989 ) =>
944990 (a -> b) ->
945991 Relation (Normalize a) (Normalize b)
946−fromFRel = fromFRel'
992+fromFRel f =
993+ let minA = minBound @a
994+ maxA = maxBound @a
995+ minB = minBound @b
996+ maxB = maxBound @b
997+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
998+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
999+ elementsA = take ccols [minA .. maxA]
1000+ elementsB = take rrows [minB .. maxB]
1001+ combinations = (,) <$> elementsA <*> elementsB
1002+ combAp = map snd . sort . map (\(a, b) -> if f a == b
1003+ then ((fromEnum a, fromEnum b), nat 1)
1004+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
1005+ mList = buildList combAp rrows
1006+ in tr $ fromLists mList
1007+ where
1008+ buildList [] _ = []
1009+ buildList l r = take r l : buildList (drop r l) r
9471010
9481011-- | Lifts a relation function to a Boolean Matrix
9491012toRel ::
@@ -953,17 +1016,17 @@ toRel ::
9531016 Enum a,
9541017 Enum b,
9551018 Eq b,
956− CountableDims a b,
1019+ CountableDimsN a b,
9571020 FLN b a
958− )
1021+ )
9591022 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
9601023toRel f =
9611024 let minA = minBound @a
9621025 maxA = maxBound @a
9631026 minB = minBound @b
9641027 maxB = maxBound @b
965− ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
966− rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
1028+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
1029+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
9671030 elementsA = take ccols [minA .. maxA]
9681031 elementsB = take rrows [minB .. maxB]
9691032 combinations = (,) <$> elementsA <*> elementsB