@@ -30,7 +30,7 @@
30-- motivation behind the library, the underlying theory, and implementation details.
30-- motivation behind the library, the underlying theory, and implementation details.
32-- This module offers many of the combinators mentioned in the work of
32-- This module offers many of the combinators mentioned in the work of
33−-- Macedo (2012) and Oliveira (2012).
33+-- Macedo (2012) and Oliveira (2012).
35-- This is an Internal module and it is no supposed to be imported.
35-- This is an Internal module and it is no supposed to be imported.
@@ -43,8 +43,8 @@ module LAoP.Matrix.Internal
44 -- There exists two type families that make it easier to write
44 -- There exists two type families that make it easier to write
45 -- matrix dimensions: 'FromNat' and 'Count'. This approach
45 -- matrix dimensions: 'FromNat' and 'Count'. This approach
46− -- leads to a very straightforward implementation
46+ -- leads to a very straightforward implementation
47− -- of LAoP combinators.
47+ -- of LAoP combinators.
49 -- * Type safe matrix representation
49 -- * Type safe matrix representation
50 Matrix (..),
50 Matrix (..),
@@ -86,7 +86,9 @@ module LAoP.Matrix.Internal
87 -- ** Get dimensions
87 -- ** Get dimensions
91 -- ** Matrix Transposition
93 -- ** Matrix Transposition
@@ -174,6 +176,7 @@ import Data.Kind
174import Data.List
176import Data.List
175import Data.Maybe
177import Data.Maybe
176import Data.Proxy
178import Data.Proxy
177import Data.Void
180import Data.Void
178import GHC.TypeLits
181import GHC.TypeLits
179import Data.Type.Equality
182import Data.Type.Equality
@@ -240,7 +243,7 @@ type Trivial a = FromNat (Count a) ~ a
241instance (Num e) => Category (Matrix e) where
244instance (Num e) => Category (Matrix e) where
242 type Object (Matrix e) a = (FL a a, Countable a)
245 type Object (Matrix e) a = (FL a a, Countable a)
243− id = iden
246+ id = iden
244 (.) = comp
247 (.) = comp
246instance NFData e => NFData (Matrix e cols rows) where
249instance NFData e => NFData (Matrix e cols rows) where
@@ -256,7 +259,6 @@ instance Eq e => Eq (Matrix e cols rows) where
256 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
259 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
258instance Num e => Num (Matrix e cols rows) where
261instance Num e => Num (Matrix e cols rows) where
260 a + b = zipWithM (+) a b
262 a + b = zipWithM (+) a b
262 a - b = zipWithM (-) a b
264 a - b = zipWithM (-) a b
@@ -315,31 +317,34 @@ class FromLists cols rows where
315 -- error if the dimensions do not match.
317 -- error if the dimensions do not match.
316 fromLists :: [[e]] -> Matrix e cols rows
318 fromLists :: [[e]] -> Matrix e cols rows
318−instance {-# OVERLAPPING #-} FromLists () () where
320+instance FromLists () () where
319 fromLists [[e]] = One e
321 fromLists [[e]] = One e
320 fromLists _ = error "Wrong dimensions"
322 fromLists _ = error "Wrong dimensions"
322−instance {-# OVERLAPPING #-} (FromLists cols ()) => FromLists (Either () cols) () where
324+instance (FromLists cols ()) => FromLists (Either () cols) () where
323 fromLists [h : t] = Join (One h) (fromLists [t])
325 fromLists [h : t] = Join (One h) (fromLists [t])
324 fromLists _ = error "Wrong dimensions"
326 fromLists _ = error "Wrong dimensions"
328+instance {-# OVERLAPPABLE #-}
326−instance {-# OVERLAPPABLE #-} (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
329+ (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
327 fromLists [l] =
330 fromLists [l] =
328 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
331 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
329 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
332 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
330 fromLists _ = error "Wrong dimensions"
333 fromLists _ = error "Wrong dimensions"
332−instance {-# OVERLAPPING #-} (FromLists () rows) => FromLists () (Either () rows) where
335+instance (FromLists () rows) => FromLists () (Either () rows) where
333 fromLists ([h] : t) = Fork (One h) (fromLists t)
336 fromLists ([h] : t) = Fork (One h) (fromLists t)
334 fromLists _ = error "Wrong dimensions"
337 fromLists _ = error "Wrong dimensions"
339+instance {-# OVERLAPPABLE #-}
336−instance {-# OVERLAPPABLE #-} (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
340+ (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
337− fromLists l@([_] : _) =
341+ fromLists l@([_] : _) =
338 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
342 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
339 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
343 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
340 fromLists _ = error "Wrong dimensions"
344 fromLists _ = error "Wrong dimensions"
342−instance {-# OVERLAPPABLE #-} (FromLists (Either a b) c, FromLists (Either a b) d, Countable c) => FromLists (Either a b) (Either c d) where
346+instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
347+ => FromLists (Either a b) (Either c d) where
343 fromLists l@(h : t) =
348 fromLists l@(h : t) =
344 let lh = length h
349 let lh = length h
345 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
350 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
@@ -366,16 +371,15 @@ matrixBuilder' f =
366matrixBuilder ::
371matrixBuilder ::
367 forall e a b.
372 forall e a b.
368 ( FLN a b,
373 ( FLN a b,
372 Bounded a,
376 Bounded a,
373 Bounded b,
377 Bounded b,
375− CountableDimsN a b
379+ Countable b
376 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
380 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
377matrixBuilder f =
381matrixBuilder f =
378− let r = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
382+ let r = fromInteger $ natVal (Proxy :: Proxy (Count b))
379 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
383 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
380 in fromLists . map (map f) . transpose . buildList r $ positions
384 in fromLists . map (map f) . transpose . buildList r $ positions
@@ -431,24 +435,7 @@ fromF ::
432 (a -> b) ->
436 (a -> b) ->
433 Matrix e (Normalize a) (Normalize b)
437 Matrix e (Normalize a) (Normalize b)
434−fromF f =
438+fromF = fromF'
435− let minA = minBound @a
439− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
440− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
441− elementsA = take ccols [minA .. maxA]
442− elementsB = take rrows [minB .. maxB]
443− combinations = (,) <$> elementsA <*> elementsB
444− combAp = map snd . sort . map (\(a, b) -> if f a == b
445− then ((fromEnum a, fromEnum b), 1)
446− else ((fromEnum a, fromEnum b), 0)) $ combinations
447− mList = buildList combAp rrows
448− in tr $ fromLists mList
451− buildList l r = take r l : buildList (drop r l) r
453-- Conversion
440-- Conversion
@@ -510,7 +497,7 @@ comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer l
510comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
497comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
511comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
498comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
512{-# NOINLINE comp #-}
499{-# NOINLINE comp #-}
513−{-# RULES
500+{-# RULES
514 "comp/iden1" forall m. comp m iden = m ;
501 "comp/iden1" forall m. comp m iden = m ;
515 "comp/iden2" forall m. comp iden m = m
502 "comp/iden2" forall m. comp iden m = m
@@ -557,24 +544,38 @@ i2 = tr p2
558-- | Obtain the number of rows.
545-- | Obtain the number of rows.
560−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
547+-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
561−-- dimensions in constant time.
548+-- dimensions in constant time. For a version that doesn't require the
562−--
549+-- constraint see 'rows''.
563−-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
564−-- exchange for performance.
565rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
550rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
566rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
551rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
553+-- | Obtain the number of rows in an inefficient manner, but without any
556+-- For a more efficient version see 'rows'.
557+rows' :: Matrix e cols rows -> Int
559+rows' (Join lhs _) = rows' lhs
560+rows' (Fork top bottom) = rows' top + rows' bottom
568-- | Obtain the number of columns.
562-- | Obtain the number of columns.
570−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
571−-- dimensions in constant time.
573−-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
564+-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
574−-- exchange for performance.
565+-- dimensions in constant time. For a version that doesn't require the
566+-- constraint see 'columns''.
575columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
567columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
576columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
568columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
570+-- | Obtain the number of columns in an inefficient manner, but without any
573+-- For a more efficient version see 'columns'.
574+columns' :: Matrix e cols rows -> Int
576+columns' (Join lhs rhs) = columns' lhs + columns' rhs
577+columns' (Fork top _) = columns' top
578-- Coproduct Bifunctor
579-- Coproduct Bifunctor
580infixl 5 -|-
581infixl 5 -|-
@@ -629,7 +630,7 @@ sndM = matrixBuilder' f
629-- | Khatri Rao Matrix product also known as matrix pairing.
630-- | Khatri Rao Matrix product also known as matrix pairing.
631-- NOTE: That this is not a true categorical product, see for instance:
632-- NOTE: That this is not a true categorical product, see for instance:
634-- | fstM . kr a b == a
635-- | fstM . kr a b == a
635-- kr a b ==> |
636-- kr a b ==> |
@@ -665,7 +666,7 @@ infixl 4 ><
665 FL (Normalize (m, n)) n,
666 FL (Normalize (m, n)) n,
666 FL (Normalize (p, q)) p,
667 FL (Normalize (p, q)) p,
667 FL (Normalize (p, q)) q
668 FL (Normalize (p, q)) q
669 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
670 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
670(><) a b =
671(><) a b =
671 let fstM' = fstM @e @m @n
672 let fstM' = fstM @e @m @n
@@ -930,24 +931,7 @@ fromFRel' ::
931 (a -> b) ->
932 (a -> b) ->
932 Relation cols rows
933 Relation cols rows
933−fromFRel' f =
934+fromFRel' = fromF'
934− let minA = minBound @a
938− ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
939− rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
940− elementsA = take ccols [minA .. maxA]
941− elementsB = take rrows [minB .. maxB]
942− combinations = (,) <$> elementsA <*> elementsB
943− combAp = map snd . sort . map (\(a, b) -> if f a == b
944− then ((fromEnum a, fromEnum b), nat 1)
945− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
946− mList = buildList combAp rrows
947− in tr $ fromLists mList
950− buildList l r = take r l : buildList (drop r l) r
952-- | Lifts functions to relations with dimensions matching @a@ and @b@
936-- | Lifts functions to relations with dimensions matching @a@ and @b@
953-- cardinality's.
937-- cardinality's.
@@ -955,28 +939,11 @@ fromFRel ::
955 forall a b.
939 forall a b.
956 ( Liftable Boolean a b,
940 ( Liftable Boolean a b,
957 CountableDimsN a b,
941 CountableDimsN a b,
958− FL (Normalize b) (Normalize a)
942+ FLN b a
960 (a -> b) ->
944 (a -> b) ->
961 Relation (Normalize a) (Normalize b)
945 Relation (Normalize a) (Normalize b)
962−fromFRel f =
946+fromFRel = fromFRel'
963− let minA = minBound @a
967− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
968− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
969− elementsA = take ccols [minA .. maxA]
970− elementsB = take rrows [minB .. maxB]
971− combinations = (,) <$> elementsA <*> elementsB
972− combAp = map snd . sort . map (\(a, b) -> if f a == b
973− then ((fromEnum a, fromEnum b), nat 1)
974− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
975− mList = buildList combAp rrows
976− in tr $ fromLists mList
979− buildList l r = take r l : buildList (drop r l) r
981-- | Lifts a relation function to a Boolean Matrix
948-- | Lifts a relation function to a Boolean Matrix
@@ -986,17 +953,17 @@ toRel ::
989− CountableDimsN a b,
956+ CountableDims a b,
992 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
959 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
994 let minA = minBound @a
961 let minA = minBound @a
995 maxA = maxBound @a
962 maxA = maxBound @a
996 minB = minBound @b
963 minB = minBound @b
997 maxB = maxBound @b
964 maxB = maxBound @b
998− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
965+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
999− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
966+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
1000 elementsA = take ccols [minA .. maxA]
967 elementsA = take ccols [minA .. maxA]
1001 elementsB = take rrows [minB .. maxB]
968 elementsB = take rrows [minB .. maxB]
1002 combinations = (,) <$> elementsA <*> elementsB
969 combinations = (,) <$> elementsA <*> elementsB