@@ -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,23 +43,23 @@ 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 (..),
5151
5252 -- * Constraint type aliases
5353 Countable,
54− CountableDimensions,
54+ CountableDims,
5555 CountableN,
56− CountableDimensionsN,
57− FromListsN,
56+ CountableDimsN,
57+ FL,
58+ FLN,
5859 Liftable,
5960 Trivial,
6061
6162 -- * Primitives
62− empty,
6363 one,
6464 join,
6565 fork,
@@ -86,7 +86,9 @@ module LAoP.Matrix.Internal
8686 -- * Misc
8787 -- ** Get dimensions
8888 columns,
89+ columns',
8990 rows,
91+ rows',
9092
9193 -- ** Matrix Transposition
9294 tr,
@@ -174,6 +176,7 @@ import Data.Kind
174176import Data.List
175177import Data.Maybe
176178import Data.Proxy
179+import Data.Typeable
177180import Data.Void
178181import GHC.TypeLits
179182import Data.Type.Equality
@@ -184,7 +187,6 @@ import qualified Prelude (id, (.))
184187
185188-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
186189data Matrix e cols rows where
187− Empty :: Matrix e Void Void
188190 One :: e -> Matrix e () ()
189191 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
190192 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
@@ -214,7 +216,6 @@ type family Count (d :: Type) :: Nat where
214216--
215217-- Thanks to Li-Yao Xia this type family is super fast.
216218type family FromNat (n :: Nat) :: Type where
217− FromNat 0 = Void
218219 FromNat 1 = ()
219220 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
220221
@@ -231,27 +232,26 @@ type family Normalize (d :: Type) :: Type where
231232-- | Constraint type synonyms to keep the type signatures less convoluted
232233type Countable a = KnownNat (Count a)
233234type CountableN a = KnownNat (Count (Normalize a))
234−type CountableDimensions a b = (Countable a, Countable b)
235−type CountableDimensionsN a b = (CountableN a, CountableN b)
236−type FromListsN e a b = FromLists e (Normalize a) (Normalize b)
235+type CountableDims a b = (Countable a, Countable b)
236+type CountableDimsN a b = (CountableN a, CountableN b)
237+type FL a b = FromLists a b
238+type FLN a b = FromLists (Normalize a) (Normalize b)
237239type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
238240type Trivial a = FromNat (Count a) ~ a
239241
240242-- | It is possible to implement a constrained version of the category type
241243-- class.
242244instance (Num e) => Category (Matrix e) where
243− type Object (Matrix e) a = (FromLists e a a, Countable a)
244− id = iden
245+ type Object (Matrix e) a = (FL a a, Countable a)
246+ id = iden
245247 (.) = comp
246248
247249instance NFData e => NFData (Matrix e cols rows) where
248− rnf Empty = ()
249250 rnf (One e) = rnf e
250251 rnf (Join a b) = rnf a `seq` rnf b
251252 rnf (Fork a b) = rnf a `seq` rnf b
252253
253254instance Eq e => Eq (Matrix e cols rows) where
254− Empty == Empty = True
255255 (One a) == (One b) = a == b
256256 (Join a b) == (Join c d) = a == c && b == d
257257 (Fork a b) == (Fork c d) = a == c && b == d
@@ -259,25 +259,21 @@ instance Eq e => Eq (Matrix e cols rows) where
259259 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
260260
261261instance Num e => Num (Matrix e cols rows) where
262−
263262 a + b = zipWithM (+) a b
264263
265264 a - b = zipWithM (-) a b
266265
267266 a * b = zipWithM (*) a b
268267
269− abs Empty = Empty
270268 abs (One a) = One (abs a)
271269 abs (Join a b) = Join (abs a) (abs b)
272270 abs (Fork a b) = Fork (abs a) (abs b)
273271
274− signum Empty = Empty
275272 signum (One a) = One (signum a)
276273 signum (Join a b) = Join (signum a) (signum b)
277274 signum (Fork a b) = Fork (signum a) (signum b)
278275
279276instance Ord e => Ord (Matrix e cols rows) where
280− Empty <= Empty = True
281277 (One a) <= (One b) = a <= b
282278 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
283279 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
@@ -286,10 +282,6 @@ instance Ord e => Ord (Matrix e cols rows) where
286282
287283-- Primitives
288284
289−-- | Empty matrix constructor
290−empty :: Matrix e Void Void
291−empty = Empty
292−
293285-- | Unit matrix constructor
294286one :: e -> Matrix e () ()
295287one = One
@@ -320,40 +312,39 @@ infixl 2 ===
320312--
321313-- Given that it is not possible to branch on types at the term level type
322314-- classes are needed very much like an inductive definition but on types.
323−class FromLists e cols rows where
315+class FromLists cols rows where
324316 -- | Build a matrix out of a list of list of elements. Throws a runtime
325317 -- error if the dimensions do not match.
326318 fromLists :: [[e]] -> Matrix e cols rows
327319
328−instance FromLists e Void Void where
329− fromLists [] = Empty
330− fromLists _ = error "Wrong dimensions"
331−
332−instance {-# OVERLAPPING #-} FromLists e () () where
320+instance FromLists () () where
333321 fromLists [[e]] = One e
334322 fromLists _ = error "Wrong dimensions"
335323
336−instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
324+instance (FromLists cols ()) => FromLists (Either () cols) () where
337325 fromLists [h : t] = Join (One h) (fromLists [t])
338326 fromLists _ = error "Wrong dimensions"
339327
340−instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), Countable a) => FromLists e (Either a b) () where
328+instance {-# OVERLAPPABLE #-}
329+ (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
341330 fromLists [l] =
342331 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
343332 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
344333 fromLists _ = error "Wrong dimensions"
345334
346−instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
335+instance (FromLists () rows) => FromLists () (Either () rows) where
347336 fromLists ([h] : t) = Fork (One h) (fromLists t)
348337 fromLists _ = error "Wrong dimensions"
349338
350−instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) where
351− fromLists l@([_] : _) =
339+instance {-# OVERLAPPABLE #-}
340+ (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
341+ fromLists l@([_] : _) =
352342 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
353343 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
354344 fromLists _ = error "Wrong dimensions"
355345
356−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
346+instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
347+ => FromLists (Either a b) (Either c d) where
357348 fromLists l@(h : t) =
358349 let lh = length h
359350 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
@@ -366,8 +357,8 @@ instance {-# OVERLAPPABLE #-} (FromLists e (Either a b) c, FromLists e (Either a
366357-- a construction function that operates with indices.
367358matrixBuilder' ::
368359 forall e cols rows.
369− ( FromLists e cols rows,
370− CountableDimensions cols rows
360+ ( FL cols rows,
361+ CountableDims cols rows
371362 ) => ((Int, Int) -> e) -> Matrix e cols rows
372363matrixBuilder' f =
373364 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
@@ -379,17 +370,16 @@ matrixBuilder' f =
379370-- a construction function that operates with arbitrary types.
380371matrixBuilder ::
381372 forall e a b.
382− ( FromListsN e a b,
383− CountableN b,
373+ ( FLN a b,
384374 Enum a,
385375 Enum b,
386376 Bounded a,
387377 Bounded b,
388378 Eq a,
389− CountableDimensionsN a b
379+ Countable b
390380 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
391381matrixBuilder f =
392− let r = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
382+ let r = fromInteger $ natVal (Proxy :: Proxy (Count b))
393383 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
394384 in fromLists . map (map f) . transpose . buildList r $ positions
395385 where
@@ -397,11 +387,11 @@ matrixBuilder f =
397387 buildList r l = take r l : buildList r (drop r l)
398388
399389-- | Constructs a column vector matrix
400−col :: (FromLists e () rows) => [e] -> Matrix e () rows
390+col :: (FL () rows) => [e] -> Matrix e () rows
401391col = fromLists . map (: [])
402392
403393-- | Constructs a row vector matrix
404−row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
394+row :: (FL cols ()) => [e] -> Matrix e cols ()
405395row = fromLists . (: [])
406396
407397-- | Lifts functions to matrices with arbitrary dimensions.
@@ -411,8 +401,8 @@ row = fromLists . (: [])
411401fromF' ::
412402 forall a b cols rows e.
413403 ( Liftable e a b,
414− CountableDimensions cols rows,
415− FromLists e rows cols
404+ CountableDims cols rows,
405+ FL rows cols
416406 ) =>
417407 (a -> b) ->
418408 Matrix e cols rows
@@ -440,35 +430,17 @@ fromF' f =
440430fromF ::
441431 forall a b e.
442432 ( Liftable e a b,
443− CountableDimensionsN a b,
444− FromListsN e b a
433+ CountableDimsN a b,
434+ FLN b a
445435 ) =>
446436 (a -> b) ->
447437 Matrix e (Normalize a) (Normalize b)
448−fromF f =
449− let minA = minBound @a
450− maxA = maxBound @a
451− minB = minBound @b
452− maxB = maxBound @b
453− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
454− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
455− elementsA = take ccols [minA .. maxA]
456− elementsB = take rrows [minB .. maxB]
457− combinations = (,) <$> elementsA <*> elementsB
458− combAp = map snd . sort . map (\(a, b) -> if f a == b
459− then ((fromEnum a, fromEnum b), 1)
460− else ((fromEnum a, fromEnum b), 0)) $ combinations
461− mList = buildList combAp rrows
462− in tr $ fromLists mList
463− where
464− buildList [] _ = []
465− buildList l r = take r l : buildList (drop r l) r
438+fromF = fromF'
466439
467440-- Conversion
468441
469442-- | Converts a matrix to a list of lists of elements.
470443toLists :: Matrix e cols rows -> [[e]]
471−toLists Empty = []
472444toLists (One e) = [[e]]
473445toLists (Fork l r) = toLists l ++ toLists r
474446toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
@@ -480,7 +452,7 @@ toList = concat . toLists
480452-- Zeros Matrix
481453
482454-- | The zero matrix. A matrix wholly filled with zeros.
483−zeros :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
455+zeros :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
484456zeros = matrixBuilder' (const 0)
485457
486458-- Ones Matrix
@@ -488,20 +460,20 @@ zeros = matrixBuilder' (const 0)
488460-- | The ones matrix. A matrix wholly filled with ones.
489461--
490462-- Also known as T (Top) matrix.
491−ones :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
463+ones :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
492464ones = matrixBuilder' (const 1)
493465
494466-- Const Matrix
495467
496468-- | The constant matrix constructor. A matrix wholly filled with a given
497469-- value.
498−constant :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => e -> Matrix e cols rows
470+constant :: (Num e, FL cols rows, CountableDims cols rows) => e -> Matrix e cols rows
499471constant e = matrixBuilder' (const e)
500472
501473-- Bang Matrix
502474
503475-- | The T (Top) row vector matrix.
504−bang :: forall e cols. (Num e, Enum e, FromLists e cols (), Countable cols) => Matrix e cols ()
476+bang :: forall e cols. (Num e, Enum e, FL cols (), Countable cols) => Matrix e cols ()
505477bang =
506478 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
507479 in fromLists [take c [1, 1 ..]]
@@ -509,7 +481,7 @@ bang =
509481-- iden Matrix
510482
511483-- | iden matrix.
512−iden :: forall e cols . (Num e, FromLists e cols cols, Countable cols) => Matrix e cols cols
484+iden :: forall e cols . (Num e, FL cols cols, Countable cols) => Matrix e cols cols
513485iden = matrixBuilder' (bool 0 1 . uncurry (==))
514486{-# NOINLINE iden #-}
515487
@@ -520,13 +492,12 @@ iden = matrixBuilder' (bool 0 1 . uncurry (==))
520492-- This definition takes advantage of divide-and-conquer and fusion laws
521493-- from LAoP.
522494comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
523−comp Empty Empty = Empty
524495comp (One a) (One b) = One (a * b)
525496comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
526497comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
527498comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
528499{-# NOINLINE comp #-}
529−{-# RULES
500+{-# RULES
530501 "comp/iden1" forall m. comp m iden = m ;
531502 "comp/iden2" forall m. comp iden m = m
532503#-}
@@ -536,7 +507,6 @@ comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
536507infixl 7 .|
537508-- | Scalar multiplication of matrices.
538509(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
539−(.|) _ Empty = Empty
540510(.|) e (One a) = One (e * a)
541511(.|) e (Join a b) = Join (e .| a) (e .| b)
542512(.|) e (Fork a b) = Fork (e .| a) (e .| b)
@@ -546,7 +516,6 @@ infixl 7 .|
546516infixl 7 ./
547517-- | Scalar multiplication of matrices.
548518(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
549−(./) Empty _ = Empty
550519(./) (One a) e = One (a / e)
551520(./) (Join a b) e = Join (a ./ e) (b ./ e)
552521(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
@@ -554,45 +523,59 @@ infixl 7 ./
554523-- Projections
555524
556525-- | Biproduct first component projection
557−p1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e (Either m n) m
526+p1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e (Either m n) m
558527p1 = join id zeros
559528
560529-- | Biproduct second component projection
561−p2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e (Either m n) n
530+p2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e (Either m n) n
562531p2 = join zeros id
563532
564533-- Injections
565534
566535-- | Biproduct first component injection
567−i1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e m (Either m n)
536+i1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e m (Either m n)
568537i1 = tr p1
569538
570539-- | Biproduct second component injection
571−i2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e n (Either m n)
540+i2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e n (Either m n)
572541i2 = tr p2
573542
574543-- Dimensions
575544
576545-- | Obtain the number of rows.
577546--
578−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
579−-- dimensions in constant time.
580−--
581−-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
582−-- exchange for performance.
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''.
583550rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
584551rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
585552
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+
586562-- | Obtain the number of columns.
587−--
588−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
589−-- dimensions in constant time.
590563--
591−-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
592−-- exchange for performance.
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''.
593567columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
594568columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
595569
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+
596579-- Coproduct Bifunctor
597580
598581infixl 5 -|-
@@ -601,11 +584,11 @@ infixl 5 -|-
601584(-|-) ::
602585 forall e n k m j.
603586 ( Num e,
604− CountableDimensions j k,
605− FromLists e k k,
606− FromLists e j k,
607− FromLists e k j,
608− FromLists e j j
587+ CountableDims j k,
588+ FL k k,
589+ FL j k,
590+ FL k j,
591+ FL j j
609592 ) =>
610593 Matrix e n k ->
611594 Matrix e m j ->
@@ -618,8 +601,8 @@ infixl 5 -|-
618601fstM ::
619602 forall e m k .
620603 ( Num e,
621− CountableDimensions k m,
622− FromLists e (Normalize (m, k)) m,
604+ CountableDims k m,
605+ FL (Normalize (m, k)) m,
623606 CountableN (m, k)
624607 ) => Matrix e (Normalize (m, k)) m
625608fstM = matrixBuilder' f
@@ -633,8 +616,8 @@ fstM = matrixBuilder' f
633616sndM ::
634617 forall e m k .
635618 ( Num e,
636− CountableDimensions k m,
637− FromLists e (Normalize (m, k)) k,
619+ CountableDims k m,
620+ FL (Normalize (m, k)) k,
638621 CountableN (m, k)
639622 ) => Matrix e (Normalize (m, k)) k
640623sndM = matrixBuilder' f
@@ -647,7 +630,7 @@ sndM = matrixBuilder' f
647630-- | Khatri Rao Matrix product also known as matrix pairing.
648631--
649632-- NOTE: That this is not a true categorical product, see for instance:
650−--
633+--
651634-- @
652635-- | fstM . kr a b == a
653636-- kr a b ==> |
@@ -658,10 +641,10 @@ sndM = matrixBuilder' f
658641kr ::
659642 forall e cols a b.
660643 ( Num e,
661− CountableDimensions a b,
644+ CountableDims a b,
662645 CountableN (a, b),
663− FromLists e (Normalize (a, b)) a,
664− FromLists e (Normalize (a, b)) b
646+ FL (Normalize (a, b)) a,
647+ FL (Normalize (a, b)) b
665648 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
666649kr a b =
667650 let fstM' = fstM @e @a @b
@@ -676,14 +659,14 @@ infixl 4 ><
676659(><) ::
677660 forall e m p n q.
678661 ( Num e,
679− CountableDimensions m n,
680− CountableDimensions p q,
681− CountableDimensionsN (m, n) (p, q),
682− FromLists e (Normalize (m, n)) m,
683− FromLists e (Normalize (m, n)) n,
684− FromLists e (Normalize (p, q)) p,
685− FromLists e (Normalize (p, q)) q
686− )
662+ CountableDims m n,
663+ CountableDims p q,
664+ CountableDimsN (m, n) (p, q),
665+ FL (Normalize (m, n)) m,
666+ FL (Normalize (m, n)) n,
667+ FL (Normalize (p, q)) p,
668+ FL (Normalize (p, q)) q
669+ )
687670 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
688671(><) a b =
689672 let fstM' = fstM @e @m @n
@@ -701,7 +684,6 @@ infixl 4 ><
701684-- @
702685abideJF :: Matrix e cols rows -> Matrix e cols rows
703686abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
704−abideJF Empty = Empty
705687abideJF (One e) = One e
706688abideJF (Join a b) = Join (abideJF a) (abideJF b)
707689abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
@@ -715,7 +697,6 @@ abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
715697-- @
716698abideFJ :: Matrix e cols rows -> Matrix e cols rows
717699abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
718−abideFJ Empty = Empty
719700abideFJ (One e) = One e
720701abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
721702abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
@@ -724,7 +705,6 @@ abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
724705
725706-- | Matrix transposition.
726707tr :: Matrix e cols rows -> Matrix e rows cols
727−tr Empty = Empty
728708tr (One e) = One e
729709tr (Join a b) = Fork (tr a) (tr b)
730710tr (Fork a b) = Join (tr a) (tr b)
@@ -733,32 +713,32 @@ tr (Fork a b) = Join (tr a) (tr b)
733713
734714-- | Selective functors 'select' operator equivalent inspired by the
735715-- ArrowMonad solution presented in the paper.
736−select :: (Num e, FromLists e b b, Countable b) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
716+select :: (Num e, FL b b, Countable b) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
737717select (Fork a b) y = y . a + b -- Divide-and-conquer law
738718select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
739719select m y = join y id . m
740720
741721branch ::
742722 ( Num e,
743− CountableDimensions a b,
744− CountableDimensions c (Either b c),
745− FromLists e c b,
746− FromLists e a b,
747− FromLists e a a,
748− FromLists e b b,
749− FromLists e c c,
750− FromLists e b a,
751− FromLists e b c,
752− FromLists e (Either b c) b,
753− FromLists e (Either b c) c
723+ CountableDims a b,
724+ CountableDims c (Either b c),
725+ FL c b,
726+ FL a b,
727+ FL a a,
728+ FL b b,
729+ FL c c,
730+ FL b a,
731+ FL b c,
732+ FL (Either b c) b,
733+ FL (Either b c) c
754734 )
755735 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
756736branch x l r = f x `select` g l `select` r
757737 where
758− f :: (Num e, Countable a, CountableDimensions b c, FromLists e a b, FromLists e c b, FromLists e b b, FromLists e b a, FromLists e a a)
738+ f :: (Num e, Countable a, CountableDims b c, FL a b, FL c b, FL b b, FL b a, FL a a)
759739 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
760740 f m = fork (tr i1) (i1 . tr i2) . m
761− g :: (Num e, CountableDimensions b c, FromLists e b c, FromLists e c c) => Matrix e a c -> Matrix e a (Either b c)
741+ g :: (Num e, CountableDims b c, FL b c, FL c c) => Matrix e a c -> Matrix e a (Either b c)
762742 g m = i2 . m
763743
764744-- McCarthy's Conditional
@@ -767,9 +747,9 @@ branch x l r = f x `select` g l `select` r
767747cond ::
768748 ( Trivial cols,
769749 Countable cols,
770− FromLists e () cols,
771− FromLists e cols (),
772− FromLists e cols cols,
750+ FL () cols,
751+ FL cols (),
752+ FL cols cols,
773753 Bounded a,
774754 Enum a,
775755 Num e,
@@ -782,9 +762,9 @@ cond p f g = join f g . grd p
782762grd ::
783763 ( Trivial q,
784764 Countable q,
785− FromLists e () q,
786− FromLists e q (),
787− FromLists e q q,
765+ FL () q,
766+ FL q (),
767+ FL q q,
788768 Bounded a,
789769 Enum a,
790770 Num e,
@@ -798,9 +778,9 @@ corr ::
798778 forall e a q .
799779 ( Trivial q,
800780 Countable q,
801− FromLists e () q,
802− FromLists e q (),
803− FromLists e q q,
781+ FL () q,
782+ FL q (),
783+ FL q q,
804784 Liftable e a Bool
805785 )
806786 => (a -> Bool) -> Matrix e q q
@@ -829,7 +809,7 @@ prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
829809 fill str = replicate (widest - length str - 2) ' ' ++ str
830810
831811-- | Matrix pretty printer
832−pretty :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> String
812+pretty :: (CountableDims cols rows, Show e) => Matrix e cols rows -> String
833813pretty m = concat
834814 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
835815 , unlines
@@ -858,12 +838,11 @@ pretty m = concat
858838 (safeGet i j m)
859839
860840-- | Matrix pretty printer
861−prettyPrint :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> IO ()
841+prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
862842prettyPrint = putStrLn . pretty
863843
864844-- | Zip two matrices with a given binary function
865845zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
866−zipWithM _ Empty Empty = Empty
867846zipWithM f (One a) (One b) = One (f a b)
868847zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
869848zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
@@ -888,14 +867,12 @@ fromBool False = nat 0
888867
889868-- | Relational negation
890869negateM :: Relation cols rows -> Relation cols rows
891−negateM Empty = Empty
892870negateM (One (Nat p)) = One (Nat (negate p))
893871negateM (Join a b) = Join (negateM a) (negateM b)
894872negateM (Fork a b) = Fork (negateM a) (negateM b)
895873
896874-- | Relational addition
897875orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
898−orM Empty Empty = Empty
899876orM (One a) (One b) = One (fromBool (toBool a || toBool b))
900877orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
901878orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
@@ -904,7 +881,6 @@ orM x@(Join _ _) y@(Fork _ _) = orM (abideJF x) y
904881
905882-- | Relational multiplication
906883andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
907−andM Empty Empty = Empty
908884andM (One a) (One b) = One (fromBool (toBool a && toBool b))
909885andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
910886andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
@@ -913,7 +889,6 @@ andM x@(Join _ _) y@(Fork _ _) = andM (abideJF x) y
913889
914890-- | Relational subtraction
915891subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
916−subM Empty Empty = Empty
917892subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
918893subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
919894subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
@@ -922,7 +897,6 @@ subM x@(Join _ _) y@(Fork _ _) = subM (abideJF x) y
922897
923898-- | Matrix relational composition.
924899compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
925−compRel Empty Empty = Empty
926900compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
927901compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
928902compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
@@ -930,7 +904,6 @@ compRel c (Join a b) = Join (compRel c a) (compRel c b) -- Join fusion
930904
931905-- | Matrix relational right division
932906divR :: Relation b c -> Relation b a -> Relation a c
933−divR Empty Empty = Empty
934907divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
935908divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
936909divR (Fork a b) c = Fork (divR a c) (divR b c)
@@ -953,58 +926,24 @@ divS s r = divL r s `intersection` divR (tr r) (tr s)
953926fromFRel' ::
954927 forall a b cols rows.
955928 ( Liftable Boolean a b,
956− CountableDimensions cols rows,
957− FromLists Boolean rows cols
929+ CountableDims cols rows,
930+ FL rows cols
958931 ) =>
959932 (a -> b) ->
960933 Relation cols rows
961−fromFRel' f =
962− let minA = minBound @a
963− maxA = maxBound @a
964− minB = minBound @b
965− maxB = maxBound @b
966− ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
967− rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
968− elementsA = take ccols [minA .. maxA]
969− elementsB = take rrows [minB .. maxB]
970− combinations = (,) <$> elementsA <*> elementsB
971− combAp = map snd . sort . map (\(a, b) -> if f a == b
972− then ((fromEnum a, fromEnum b), nat 1)
973− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
974− mList = buildList combAp rrows
975− in tr $ fromLists mList
976− where
977− buildList [] _ = []
978− buildList l r = take r l : buildList (drop r l) r
934+fromFRel' = fromF'
979935
980936-- | Lifts functions to relations with dimensions matching @a@ and @b@
981937-- cardinality's.
982938fromFRel ::
983939 forall a b.
984940 ( Liftable Boolean a b,
985− CountableDimensionsN a b,
986− FromLists Boolean (Normalize b) (Normalize a)
941+ CountableDimsN a b,
942+ FLN b a
987943 ) =>
988944 (a -> b) ->
989945 Relation (Normalize a) (Normalize b)
990−fromFRel f =
991− let minA = minBound @a
992− maxA = maxBound @a
993− minB = minBound @b
994− maxB = maxBound @b
995− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
996− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
997− elementsA = take ccols [minA .. maxA]
998− elementsB = take rrows [minB .. maxB]
999− combinations = (,) <$> elementsA <*> elementsB
1000− combAp = map snd . sort . map (\(a, b) -> if f a == b
1001− then ((fromEnum a, fromEnum b), nat 1)
1002− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
1003− mList = buildList combAp rrows
1004− in tr $ fromLists mList
1005− where
1006− buildList [] _ = []
1007− buildList l r = take r l : buildList (drop r l) r
946+fromFRel = fromFRel'
1008947
1009948-- | Lifts a relation function to a Boolean Matrix
1010949toRel ::
@@ -1014,17 +953,17 @@ toRel ::
1014953 Enum a,
1015954 Enum b,
1016955 Eq b,
1017− CountableDimensionsN a b,
1018− FromListsN Boolean b a
1019− )
956+ CountableDims a b,
957+ FLN b a
958+ )
1020959 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
1021960toRel f =
1022961 let minA = minBound @a
1023962 maxA = maxBound @a
1024963 minB = minBound @b
1025964 maxB = maxBound @b
1026− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
1027− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
965+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
966+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
1028967 elementsA = take ccols [minA .. maxA]
1029968 elementsB = take rrows [minB .. maxB]
1030969 combinations = (,) <$> elementsA <*> elementsB