@@ -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,14 @@ 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
52− -- * Constraint type aliases
53− Countable,
54− CountableDims,
55− CountableN,
56− CountableDimsN,
57− FL,
58− FLN,
59− Liftable,
60− Trivial,
61−
6252 -- * Primitives
53+ empty,
6354 one,
6455 join,
6556 fork,
@@ -86,9 +77,7 @@ module LAoP.Matrix.Internal
8677 -- * Misc
8778 -- ** Get dimensions
8879 columns,
89− columns',
9080 rows,
91− rows',
9281
9382 -- ** Matrix Transposition
9483 tr,
@@ -130,7 +119,6 @@ module LAoP.Matrix.Internal
130119
131120 -- | Note that given the restrictions imposed it is not possible to
132121 -- implement the standard type classes present in standard Haskell.
133−
134122 -- *** Matrix pairing projections
135123 fstM,
136124 sndM,
@@ -176,17 +164,17 @@ import Data.Kind
176164import Data.List
177165import Data.Maybe
178166import Data.Proxy
179−import Data.Typeable
180167import Data.Void
181168import GHC.TypeLits
182169import Data.Type.Equality
183170import GHC.Generics
184171import Control.DeepSeq
185−import Prelude hiding (id, (.))
186−import qualified Prelude (id, (.))
172+import Control.Category
173+import Prelude hiding ((.))
187174
188175-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
189176data Matrix e cols rows where
177+ Empty :: Matrix e Void Void
190178 One :: e -> Matrix e () ()
191179 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
192180 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
@@ -216,6 +204,7 @@ type family Count (d :: Type) :: Nat where
216204--
217205-- Thanks to Li-Yao Xia this type family is super fast.
218206type family FromNat (n :: Nat) :: Type where
207+ FromNat 0 = Void
219208 FromNat 1 = ()
220209 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
221210
@@ -232,26 +221,29 @@ type family Normalize (d :: Type) :: Type where
232221-- | Constraint type synonyms to keep the type signatures less convoluted
233222type Countable a = KnownNat (Count a)
234223type CountableN a = KnownNat (Count (Normalize a))
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)
224+type CountableDimensions a b = (Countable a, Countable b)
225+type CountableDimensionsN a b = (CountableN a, CountableN b)
226+type FromListsN e a b = FromLists e (Normalize a) (Normalize b)
239227type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
240228type Trivial a = FromNat (Count a) ~ a
241229
242−-- | It is possible to implement a constrained version of the category type
243−-- class.
230+-- | It isn't possible to implement the 'id' function so it's
231+-- implementation is 'undefined'. However 'comp' can be and this partial
232+-- class implementation exists just to make the code more readable.
233+--
234+-- Please use 'iden' instead.
244235instance (Num e) => Category (Matrix e) where
245− type Object (Matrix e) a = (FL a a, Countable a)
246− id = iden
247− (.) = comp
236+ id = undefined
237+ (.) = comp
248238
249239instance NFData e => NFData (Matrix e cols rows) where
240+ rnf Empty = ()
250241 rnf (One e) = rnf e
251242 rnf (Join a b) = rnf a `seq` rnf b
252243 rnf (Fork a b) = rnf a `seq` rnf b
253244
254245instance Eq e => Eq (Matrix e cols rows) where
246+ Empty == Empty = True
255247 (One a) == (One b) = a == b
256248 (Join a b) == (Join c d) = a == c && b == d
257249 (Fork a b) == (Fork c d) = a == c && b == d
@@ -259,21 +251,25 @@ instance Eq e => Eq (Matrix e cols rows) where
259251 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
260252
261253instance Num e => Num (Matrix e cols rows) where
254+
262255 a + b = zipWithM (+) a b
263256
264257 a - b = zipWithM (-) a b
265258
266259 a * b = zipWithM (*) a b
267260
261+ abs Empty = Empty
268262 abs (One a) = One (abs a)
269263 abs (Join a b) = Join (abs a) (abs b)
270264 abs (Fork a b) = Fork (abs a) (abs b)
271265
266+ signum Empty = Empty
272267 signum (One a) = One (signum a)
273268 signum (Join a b) = Join (signum a) (signum b)
274269 signum (Fork a b) = Fork (signum a) (signum b)
275270
276271instance Ord e => Ord (Matrix e cols rows) where
272+ Empty <= Empty = True
277273 (One a) <= (One b) = a <= b
278274 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
279275 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
@@ -282,6 +278,10 @@ instance Ord e => Ord (Matrix e cols rows) where
282278
283279-- Primitives
284280
281+-- | Empty matrix constructor
282+empty :: Matrix e Void Void
283+empty = Empty
284+
285285-- | Unit matrix constructor
286286one :: e -> Matrix e () ()
287287one = One
@@ -312,39 +312,40 @@ infixl 2 ===
312312--
313313-- Given that it is not possible to branch on types at the term level type
314314-- classes are needed very much like an inductive definition but on types.
315−class FromLists cols rows where
315+class FromLists e cols rows where
316316 -- | Build a matrix out of a list of list of elements. Throws a runtime
317317 -- error if the dimensions do not match.
318318 fromLists :: [[e]] -> Matrix e cols rows
319319
320−instance FromLists () () where
320+instance FromLists e Void Void where
321+ fromLists [] = Empty
322+ fromLists _ = error "Wrong dimensions"
323+
324+instance {-# OVERLAPPING #-} FromLists e () () where
321325 fromLists [[e]] = One e
322326 fromLists _ = error "Wrong dimensions"
323327
324−instance (FromLists cols ()) => FromLists (Either () cols) () where
328+instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
325329 fromLists [h : t] = Join (One h) (fromLists [t])
326330 fromLists _ = error "Wrong dimensions"
327331
328−instance {-# OVERLAPPABLE #-}
329− (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
332+instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), Countable a) => FromLists e (Either a b) () where
330333 fromLists [l] =
331334 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
332335 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
333336 fromLists _ = error "Wrong dimensions"
334337
335−instance (FromLists () rows) => FromLists () (Either () rows) where
338+instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
336339 fromLists ([h] : t) = Fork (One h) (fromLists t)
337340 fromLists _ = error "Wrong dimensions"
338341
339−instance {-# OVERLAPPABLE #-}
340− (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
341− fromLists l@([_] : _) =
342+instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) where
343+ fromLists l@([_] : _) =
342344 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
343345 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
344346 fromLists _ = error "Wrong dimensions"
345347
346−instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
347− => FromLists (Either a b) (Either c d) where
348+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
348349 fromLists l@(h : t) =
349350 let lh = length h
350351 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
@@ -357,8 +358,8 @@ instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
357358-- a construction function that operates with indices.
358359matrixBuilder' ::
359360 forall e cols rows.
360− ( FL cols rows,
361− CountableDims cols rows
361+ ( FromLists e cols rows,
362+ CountableDimensions cols rows
362363 ) => ((Int, Int) -> e) -> Matrix e cols rows
363364matrixBuilder' f =
364365 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
@@ -370,16 +371,17 @@ matrixBuilder' f =
370371-- a construction function that operates with arbitrary types.
371372matrixBuilder ::
372373 forall e a b.
373− ( FLN a b,
374+ ( FromListsN e a b,
375+ CountableN b,
374376 Enum a,
375377 Enum b,
376378 Bounded a,
377379 Bounded b,
378380 Eq a,
379− Countable b
381+ CountableDimensionsN a b
380382 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
381383matrixBuilder f =
382− let r = fromInteger $ natVal (Proxy :: Proxy (Count b))
384+ let r = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
383385 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
384386 in fromLists . map (map f) . transpose . buildList r $ positions
385387 where
@@ -387,11 +389,11 @@ matrixBuilder f =
387389 buildList r l = take r l : buildList r (drop r l)
388390
389391-- | Constructs a column vector matrix
390−col :: (FL () rows) => [e] -> Matrix e () rows
392+col :: (FromLists e () rows) => [e] -> Matrix e () rows
391393col = fromLists . map (: [])
392394
393395-- | Constructs a row vector matrix
394−row :: (FL cols ()) => [e] -> Matrix e cols ()
396+row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
395397row = fromLists . (: [])
396398
397399-- | Lifts functions to matrices with arbitrary dimensions.
@@ -401,8 +403,8 @@ row = fromLists . (: [])
401403fromF' ::
402404 forall a b cols rows e.
403405 ( Liftable e a b,
404− CountableDims cols rows,
405− FL rows cols
406+ CountableDimensions cols rows,
407+ FromLists e rows cols
406408 ) =>
407409 (a -> b) ->
408410 Matrix e cols rows
@@ -430,17 +432,35 @@ fromF' f =
430432fromF ::
431433 forall a b e.
432434 ( Liftable e a b,
433− CountableDimsN a b,
434− FLN b a
435+ CountableDimensionsN a b,
436+ FromListsN e b a
435437 ) =>
436438 (a -> b) ->
437439 Matrix e (Normalize a) (Normalize b)
438−fromF = fromF'
440+fromF f =
441+ let minA = minBound @a
442+ maxA = maxBound @a
443+ minB = minBound @b
444+ maxB = maxBound @b
445+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
446+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
447+ elementsA = take ccols [minA .. maxA]
448+ elementsB = take rrows [minB .. maxB]
449+ combinations = (,) <$> elementsA <*> elementsB
450+ combAp = map snd . sort . map (\(a, b) -> if f a == b
451+ then ((fromEnum a, fromEnum b), 1)
452+ else ((fromEnum a, fromEnum b), 0)) $ combinations
453+ mList = buildList combAp rrows
454+ in tr $ fromLists mList
455+ where
456+ buildList [] _ = []
457+ buildList l r = take r l : buildList (drop r l) r
439458
440459-- Conversion
441460
442461-- | Converts a matrix to a list of lists of elements.
443462toLists :: Matrix e cols rows -> [[e]]
463+toLists Empty = []
444464toLists (One e) = [[e]]
445465toLists (Fork l r) = toLists l ++ toLists r
446466toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
@@ -452,7 +472,7 @@ toList = concat . toLists
452472-- Zeros Matrix
453473
454474-- | The zero matrix. A matrix wholly filled with zeros.
455−zeros :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
475+zeros :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
456476zeros = matrixBuilder' (const 0)
457477
458478-- Ones Matrix
@@ -460,20 +480,20 @@ zeros = matrixBuilder' (const 0)
460480-- | The ones matrix. A matrix wholly filled with ones.
461481--
462482-- Also known as T (Top) matrix.
463−ones :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
483+ones :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
464484ones = matrixBuilder' (const 1)
465485
466486-- Const Matrix
467487
468488-- | The constant matrix constructor. A matrix wholly filled with a given
469489-- value.
470−constant :: (Num e, FL cols rows, CountableDims cols rows) => e -> Matrix e cols rows
490+constant :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => e -> Matrix e cols rows
471491constant e = matrixBuilder' (const e)
472492
473493-- Bang Matrix
474494
475495-- | The T (Top) row vector matrix.
476−bang :: forall e cols. (Num e, Enum e, FL cols (), Countable cols) => Matrix e cols ()
496+bang :: forall e cols. (Num e, Enum e, FromLists e cols (), Countable cols) => Matrix e cols ()
477497bang =
478498 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
479499 in fromLists [take c [1, 1 ..]]
@@ -481,7 +501,7 @@ bang =
481501-- iden Matrix
482502
483503-- | iden matrix.
484−iden :: forall e cols . (Num e, FL cols cols, Countable cols) => Matrix e cols cols
504+iden :: (Num e, FromLists e cols cols, Countable cols) => Matrix e cols cols
485505iden = matrixBuilder' (bool 0 1 . uncurry (==))
486506{-# NOINLINE iden #-}
487507
@@ -492,12 +512,13 @@ iden = matrixBuilder' (bool 0 1 . uncurry (==))
492512-- This definition takes advantage of divide-and-conquer and fusion laws
493513-- from LAoP.
494514comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
515+comp Empty Empty = Empty
495516comp (One a) (One b) = One (a * b)
496517comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
497518comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
498519comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
499520{-# NOINLINE comp #-}
500−{-# RULES
521+{-# RULES
501522 "comp/iden1" forall m. comp m iden = m ;
502523 "comp/iden2" forall m. comp iden m = m
503524#-}
@@ -507,6 +528,7 @@ comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
507528infixl 7 .|
508529-- | Scalar multiplication of matrices.
509530(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
531+(.|) _ Empty = Empty
510532(.|) e (One a) = One (e * a)
511533(.|) e (Join a b) = Join (e .| a) (e .| b)
512534(.|) e (Fork a b) = Fork (e .| a) (e .| b)
@@ -516,6 +538,7 @@ infixl 7 .|
516538infixl 7 ./
517539-- | Scalar multiplication of matrices.
518540(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
541+(./) Empty _ = Empty
519542(./) (One a) e = One (a / e)
520543(./) (Join a b) e = Join (a ./ e) (b ./ e)
521544(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
@@ -523,59 +546,45 @@ infixl 7 ./
523546-- Projections
524547
525548-- | Biproduct first component projection
526−p1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e (Either m n) m
527−p1 = join id zeros
549+p1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e (Either m n) m
550+p1 = join iden zeros
528551
529552-- | Biproduct second component projection
530−p2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e (Either m n) n
531−p2 = join zeros id
553+p2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e (Either m n) n
554+p2 = join zeros iden
532555
533556-- Injections
534557
535558-- | Biproduct first component injection
536−i1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e m (Either m n)
559+i1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e m (Either m n)
537560i1 = tr p1
538561
539562-- | Biproduct second component injection
540−i2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e n (Either m n)
563+i2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e n (Either m n)
541564i2 = tr p2
542565
543566-- Dimensions
544567
545568-- | Obtain the number of rows.
546569--
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''.
570+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
571+-- dimensions in constant time.
572+--
573+-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
574+-- exchange for performance.
550575rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
551576rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
552577
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−
562578-- | Obtain the number of columns.
579+--
580+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
581+-- dimensions in constant time.
563582--
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''.
583+-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
584+-- exchange for performance.
567585columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
568586columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
569587
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−
579588-- Coproduct Bifunctor
580589
581590infixl 5 -|-
@@ -584,11 +593,11 @@ infixl 5 -|-
584593(-|-) ::
585594 forall e n k m j.
586595 ( Num e,
587− CountableDims j k,
588− FL k k,
589− FL j k,
590− FL k j,
591− FL j j
596+ CountableDimensions j k,
597+ FromLists e k k,
598+ FromLists e j k,
599+ FromLists e k j,
600+ FromLists e j j
592601 ) =>
593602 Matrix e n k ->
594603 Matrix e m j ->
@@ -601,8 +610,8 @@ infixl 5 -|-
601610fstM ::
602611 forall e m k .
603612 ( Num e,
604− CountableDims k m,
605− FL (Normalize (m, k)) m,
613+ CountableDimensions k m,
614+ FromLists e (Normalize (m, k)) m,
606615 CountableN (m, k)
607616 ) => Matrix e (Normalize (m, k)) m
608617fstM = matrixBuilder' f
@@ -616,8 +625,8 @@ fstM = matrixBuilder' f
616625sndM ::
617626 forall e m k .
618627 ( Num e,
619− CountableDims k m,
620− FL (Normalize (m, k)) k,
628+ CountableDimensions k m,
629+ FromLists e (Normalize (m, k)) k,
621630 CountableN (m, k)
622631 ) => Matrix e (Normalize (m, k)) k
623632sndM = matrixBuilder' f
@@ -630,7 +639,7 @@ sndM = matrixBuilder' f
630639-- | Khatri Rao Matrix product also known as matrix pairing.
631640--
632641-- NOTE: That this is not a true categorical product, see for instance:
633−--
642+--
634643-- @
635644-- | fstM . kr a b == a
636645-- kr a b ==> |
@@ -641,10 +650,10 @@ sndM = matrixBuilder' f
641650kr ::
642651 forall e cols a b.
643652 ( Num e,
644− CountableDims a b,
653+ CountableDimensions a b,
645654 CountableN (a, b),
646− FL (Normalize (a, b)) a,
647− FL (Normalize (a, b)) b
655+ FromLists e (Normalize (a, b)) a,
656+ FromLists e (Normalize (a, b)) b
648657 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
649658kr a b =
650659 let fstM' = fstM @e @a @b
@@ -659,14 +668,14 @@ infixl 4 ><
659668(><) ::
660669 forall e m p n q.
661670 ( Num e,
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− )
671+ CountableDimensions m n,
672+ CountableDimensions p q,
673+ CountableDimensionsN (m, n) (p, q),
674+ FromLists e (Normalize (m, n)) m,
675+ FromLists e (Normalize (m, n)) n,
676+ FromLists e (Normalize (p, q)) p,
677+ FromLists e (Normalize (p, q)) q
678+ )
670679 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
671680(><) a b =
672681 let fstM' = fstM @e @m @n
@@ -684,6 +693,7 @@ infixl 4 ><
684693-- @
685694abideJF :: Matrix e cols rows -> Matrix e cols rows
686695abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
696+abideJF Empty = Empty
687697abideJF (One e) = One e
688698abideJF (Join a b) = Join (abideJF a) (abideJF b)
689699abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
@@ -697,6 +707,7 @@ abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
697707-- @
698708abideFJ :: Matrix e cols rows -> Matrix e cols rows
699709abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
710+abideFJ Empty = Empty
700711abideFJ (One e) = One e
701712abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
702713abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
@@ -705,6 +716,7 @@ abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
705716
706717-- | Matrix transposition.
707718tr :: Matrix e cols rows -> Matrix e rows cols
719+tr Empty = Empty
708720tr (One e) = One e
709721tr (Join a b) = Fork (tr a) (tr b)
710722tr (Fork a b) = Join (tr a) (tr b)
@@ -713,32 +725,32 @@ tr (Fork a b) = Join (tr a) (tr b)
713725
714726-- | Selective functors 'select' operator equivalent inspired by the
715727-- ArrowMonad solution presented in the paper.
716−select :: (Num e, FL b b, Countable b) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
728+select :: (Num e, FromLists e b b, Countable b) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
717729select (Fork a b) y = y . a + b -- Divide-and-conquer law
718730select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
719−select m y = join y id . m
731+select m y = join y iden . m
720732
721733branch ::
722734 ( Num e,
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
735+ CountableDimensions a b,
736+ CountableDimensions c (Either b c),
737+ FromLists e c b,
738+ FromLists e a b,
739+ FromLists e a a,
740+ FromLists e b b,
741+ FromLists e c c,
742+ FromLists e b a,
743+ FromLists e b c,
744+ FromLists e (Either b c) b,
745+ FromLists e (Either b c) c
734746 )
735747 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
736748branch x l r = f x `select` g l `select` r
737749 where
738− f :: (Num e, Countable a, CountableDims b c, FL a b, FL c b, FL b b, FL b a, FL a a)
750+ 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)
739751 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
740752 f m = fork (tr i1) (i1 . tr i2) . m
741− g :: (Num e, CountableDims b c, FL b c, FL c c) => Matrix e a c -> Matrix e a (Either b c)
753+ g :: (Num e, CountableDimensions b c, FromLists e b c, FromLists e c c) => Matrix e a c -> Matrix e a (Either b c)
742754 g m = i2 . m
743755
744756-- McCarthy's Conditional
@@ -747,9 +759,9 @@ branch x l r = f x `select` g l `select` r
747759cond ::
748760 ( Trivial cols,
749761 Countable cols,
750− FL () cols,
751− FL cols (),
752− FL cols cols,
762+ FromLists e () cols,
763+ FromLists e cols (),
764+ FromLists e cols cols,
753765 Bounded a,
754766 Enum a,
755767 Num e,
@@ -762,9 +774,9 @@ cond p f g = join f g . grd p
762774grd ::
763775 ( Trivial q,
764776 Countable q,
765− FL () q,
766− FL q (),
767− FL q q,
777+ FromLists e () q,
778+ FromLists e q (),
779+ FromLists e q q,
768780 Bounded a,
769781 Enum a,
770782 Num e,
@@ -778,14 +790,14 @@ corr ::
778790 forall e a q .
779791 ( Trivial q,
780792 Countable q,
781− FL () q,
782− FL q (),
783− FL q q,
793+ FromLists e () q,
794+ FromLists e q (),
795+ FromLists e q q,
784796 Liftable e a Bool
785797 )
786798 => (a -> Bool) -> Matrix e q q
787799corr p = let f = fromF' p :: Matrix e q ()
788− in kr f (id :: Matrix e q q)
800+ in kr f (iden :: Matrix e q q)
789801
790802-- Pretty print
791803
@@ -809,7 +821,7 @@ prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
809821 fill str = replicate (widest - length str - 2) ' ' ++ str
810822
811823-- | Matrix pretty printer
812−pretty :: (CountableDims cols rows, Show e) => Matrix e cols rows -> String
824+pretty :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> String
813825pretty m = concat
814826 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
815827 , unlines
@@ -838,11 +850,12 @@ pretty m = concat
838850 (safeGet i j m)
839851
840852-- | Matrix pretty printer
841−prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
853+prettyPrint :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> IO ()
842854prettyPrint = putStrLn . pretty
843855
844856-- | Zip two matrices with a given binary function
845857zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
858+zipWithM _ Empty Empty = Empty
846859zipWithM f (One a) (One b) = One (f a b)
847860zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
848861zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
@@ -867,12 +880,14 @@ fromBool False = nat 0
867880
868881-- | Relational negation
869882negateM :: Relation cols rows -> Relation cols rows
883+negateM Empty = Empty
870884negateM (One (Nat p)) = One (Nat (negate p))
871885negateM (Join a b) = Join (negateM a) (negateM b)
872886negateM (Fork a b) = Fork (negateM a) (negateM b)
873887
874888-- | Relational addition
875889orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
890+orM Empty Empty = Empty
876891orM (One a) (One b) = One (fromBool (toBool a || toBool b))
877892orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
878893orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
@@ -881,6 +896,7 @@ orM x@(Join _ _) y@(Fork _ _) = orM (abideJF x) y
881896
882897-- | Relational multiplication
883898andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
899+andM Empty Empty = Empty
884900andM (One a) (One b) = One (fromBool (toBool a && toBool b))
885901andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
886902andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
@@ -889,6 +905,7 @@ andM x@(Join _ _) y@(Fork _ _) = andM (abideJF x) y
889905
890906-- | Relational subtraction
891907subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
908+subM Empty Empty = Empty
892909subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
893910subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
894911subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
@@ -897,6 +914,7 @@ subM x@(Join _ _) y@(Fork _ _) = subM (abideJF x) y
897914
898915-- | Matrix relational composition.
899916compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
917+compRel Empty Empty = Empty
900918compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
901919compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
902920compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
@@ -904,6 +922,7 @@ compRel c (Join a b) = Join (compRel c a) (compRel c b) -- Join fusion
904922
905923-- | Matrix relational right division
906924divR :: Relation b c -> Relation b a -> Relation a c
925+divR Empty Empty = Empty
907926divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
908927divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
909928divR (Fork a b) c = Fork (divR a c) (divR b c)
@@ -926,24 +945,58 @@ divS s r = divL r s `intersection` divR (tr r) (tr s)
926945fromFRel' ::
927946 forall a b cols rows.
928947 ( Liftable Boolean a b,
929− CountableDims cols rows,
930− FL rows cols
948+ CountableDimensions cols rows,
949+ FromLists Boolean rows cols
931950 ) =>
932951 (a -> b) ->
933952 Relation cols rows
934−fromFRel' = fromF'
953+fromFRel' f =
954+ let minA = minBound @a
955+ maxA = maxBound @a
956+ minB = minBound @b
957+ maxB = maxBound @b
958+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
959+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
960+ elementsA = take ccols [minA .. maxA]
961+ elementsB = take rrows [minB .. maxB]
962+ combinations = (,) <$> elementsA <*> elementsB
963+ combAp = map snd . sort . map (\(a, b) -> if f a == b
964+ then ((fromEnum a, fromEnum b), nat 1)
965+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
966+ mList = buildList combAp rrows
967+ in tr $ fromLists mList
968+ where
969+ buildList [] _ = []
970+ buildList l r = take r l : buildList (drop r l) r
935971
936972-- | Lifts functions to relations with dimensions matching @a@ and @b@
937973-- cardinality's.
938974fromFRel ::
939975 forall a b.
940976 ( Liftable Boolean a b,
941− CountableDimsN a b,
942− FLN b a
977+ CountableDimensionsN a b,
978+ FromLists Boolean (Normalize b) (Normalize a)
943979 ) =>
944980 (a -> b) ->
945981 Relation (Normalize a) (Normalize b)
946−fromFRel = fromFRel'
982+fromFRel f =
983+ let minA = minBound @a
984+ maxA = maxBound @a
985+ minB = minBound @b
986+ maxB = maxBound @b
987+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
988+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
989+ elementsA = take ccols [minA .. maxA]
990+ elementsB = take rrows [minB .. maxB]
991+ combinations = (,) <$> elementsA <*> elementsB
992+ combAp = map snd . sort . map (\(a, b) -> if f a == b
993+ then ((fromEnum a, fromEnum b), nat 1)
994+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
995+ mList = buildList combAp rrows
996+ in tr $ fromLists mList
997+ where
998+ buildList [] _ = []
999+ buildList l r = take r l : buildList (drop r l) r
9471000
9481001-- | Lifts a relation function to a Boolean Matrix
9491002toRel ::
@@ -953,17 +1006,17 @@ toRel ::
9531006 Enum a,
9541007 Enum b,
9551008 Eq b,
956− CountableDims a b,
957− FLN b a
958− )
1009+ CountableDimensionsN a b,
1010+ FromListsN Boolean b a
1011+ )
9591012 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
9601013toRel f =
9611014 let minA = minBound @a
9621015 maxA = maxBound @a
9631016 minB = minBound @b
9641017 maxB = maxBound @b
965− ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
966− rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
1018+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
1019+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
9671020 elementsA = take ccols [minA .. maxA]
9681021 elementsB = take rrows [minB .. maxB]
9691022 combinations = (,) <$> elementsA <*> elementsB