@@ -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,14 +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
52+ -- * Constraint type aliases
53+ Countable,
54+ CountableDims,
55+ CountableN,
56+ CountableDimsN,
57+ FL,
58+ FLN,
59+ Liftable,
60+ Trivial,
61+
5262 -- * Primitives
53− empty,
5463 one,
5564 join,
5665 fork,
@@ -66,6 +75,7 @@ module LAoP.Matrix.Internal
6675 toLists,
6776 toList,
6877 matrixBuilder,
78+ matrixBuilder',
6979 row,
7080 col,
7181 zeros,
@@ -76,11 +86,17 @@ module LAoP.Matrix.Internal
7686 -- * Misc
7787 -- ** Get dimensions
7888 columns,
89+ columns',
7990 rows,
91+ rows',
8092
8193 -- ** Matrix Transposition
8294 tr,
8395
96+ -- ** Scalar multiplication/division of matrices
97+ (.|),
98+ (./),
99+
84100 -- ** Selective operator
85101 select,
86102 branch,
@@ -114,6 +130,7 @@ module LAoP.Matrix.Internal
114130
115131 -- | Note that given the restrictions imposed it is not possible to
116132 -- implement the standard type classes present in standard Haskell.
133+
117134 -- *** Matrix pairing projections
118135 fstM,
119136 sndM,
@@ -159,17 +176,17 @@ import Data.Kind
159176import Data.List
160177import Data.Maybe
161178import Data.Proxy
179+import Data.Typeable
162180import Data.Void
163181import GHC.TypeLits
164182import Data.Type.Equality
165183import GHC.Generics
166184import Control.DeepSeq
167−import Control.Category
168−import Prelude hiding ((.))
185+import Prelude hiding (id, (.))
186+import qualified Prelude (id, (.))
169187
170188-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
171189data Matrix e cols rows where
172− Empty :: Matrix e Void Void
173190 One :: e -> Matrix e () ()
174191 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
175192 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
@@ -199,7 +216,6 @@ type family Count (d :: Type) :: Nat where
199216--
200217-- Thanks to Li-Yao Xia this type family is super fast.
201218type family FromNat (n :: Nat) :: Type where
202− FromNat 0 = Void
203219 FromNat 1 = ()
204220 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
205221
@@ -216,29 +232,26 @@ type family Normalize (d :: Type) :: Type where
216232-- | Constraint type synonyms to keep the type signatures less convoluted
217233type Countable a = KnownNat (Count a)
218234type CountableN a = KnownNat (Count (Normalize a))
219−type CountableDimensions a b = (Countable a, Countable b)
220−type CountableDimensionsN a b = (CountableN a, CountableN b)
221−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)
222239type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
223240type Trivial a = FromNat (Count a) ~ a
224241
225−-- | It isn't possible to implement the 'id' function so it's
226−-- implementation is 'undefined'. However 'comp' can be and this partial
227−-- class implementation exists just to make the code more readable.
228−--
229−-- Please use 'iden' instead.
242+-- | It is possible to implement a constrained version of the category type
243+-- class.
230244instance (Num e) => Category (Matrix e) where
231− id = undefined
232− (.) = comp
245+ type Object (Matrix e) a = (FL a a, Countable a)
246+ id = iden
247+ (.) = comp
233248
234249instance NFData e => NFData (Matrix e cols rows) where
235− rnf Empty = ()
236250 rnf (One e) = rnf e
237251 rnf (Join a b) = rnf a `seq` rnf b
238252 rnf (Fork a b) = rnf a `seq` rnf b
239253
240254instance Eq e => Eq (Matrix e cols rows) where
241− Empty == Empty = True
242255 (One a) == (One b) = a == b
243256 (Join a b) == (Join c d) = a == c && b == d
244257 (Fork a b) == (Fork c d) = a == c && b == d
@@ -246,25 +259,21 @@ instance Eq e => Eq (Matrix e cols rows) where
246259 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
247260
248261instance Num e => Num (Matrix e cols rows) where
249−
250262 a + b = zipWithM (+) a b
251263
252264 a - b = zipWithM (-) a b
253265
254266 a * b = zipWithM (*) a b
255267
256− abs Empty = Empty
257268 abs (One a) = One (abs a)
258269 abs (Join a b) = Join (abs a) (abs b)
259270 abs (Fork a b) = Fork (abs a) (abs b)
260271
261− signum Empty = Empty
262272 signum (One a) = One (signum a)
263273 signum (Join a b) = Join (signum a) (signum b)
264274 signum (Fork a b) = Fork (signum a) (signum b)
265275
266276instance Ord e => Ord (Matrix e cols rows) where
267− Empty <= Empty = True
268277 (One a) <= (One b) = a <= b
269278 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
270279 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
@@ -273,10 +282,6 @@ instance Ord e => Ord (Matrix e cols rows) where
273282
274283-- Primitives
275284
276−-- | Empty matrix constructor
277−empty :: Matrix e Void Void
278−empty = Empty
279−
280285-- | Unit matrix constructor
281286one :: e -> Matrix e () ()
282287one = One
@@ -307,67 +312,86 @@ infixl 2 ===
307312--
308313-- Given that it is not possible to branch on types at the term level type
309314-- classes are needed very much like an inductive definition but on types.
310−class FromLists e cols rows where
315+class FromLists cols rows where
311316 -- | Build a matrix out of a list of list of elements. Throws a runtime
312317 -- error if the dimensions do not match.
313318 fromLists :: [[e]] -> Matrix e cols rows
314319
315−instance FromLists e Void Void where
316− fromLists [] = Empty
317− fromLists _ = error "Wrong dimensions"
318−
319−instance {-# OVERLAPPING #-} FromLists e () () where
320+instance FromLists () () where
320321 fromLists [[e]] = One e
321322 fromLists _ = error "Wrong dimensions"
322323
323−instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
324+instance (FromLists cols ()) => FromLists (Either () cols) () where
324325 fromLists [h : t] = Join (One h) (fromLists [t])
325326 fromLists _ = error "Wrong dimensions"
326327
327−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
328330 fromLists [l] =
329331 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
330332 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
331333 fromLists _ = error "Wrong dimensions"
332334
333−instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
335+instance (FromLists () rows) => FromLists () (Either () rows) where
334336 fromLists ([h] : t) = Fork (One h) (fromLists t)
335337 fromLists _ = error "Wrong dimensions"
336338
337−instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) where
338− fromLists l@([_] : _) =
339+instance {-# OVERLAPPABLE #-}
340+ (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
341+ fromLists l@([_] : _) =
339342 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
340343 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
341344 fromLists _ = error "Wrong dimensions"
342345
343−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
344348 fromLists l@(h : t) =
345349 let lh = length h
346350 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
347− condition = all (== lh) (map length t)
351+ condition = all ((== lh) . length) t
348352 in if lh > 0 && condition
349353 then Fork (fromLists (take rowsC l)) (fromLists (drop rowsC l))
350354 else error "Not all rows have the same length"
351355
352356-- | Matrix builder function. Constructs a matrix provided with
353−-- a construction function.
354−matrixBuilder ::
357+-- a construction function that operates with indices.
358+matrixBuilder' ::
355359 forall e cols rows.
356− ( FromLists e cols rows,
357− CountableDimensions cols rows
360+ ( FL cols rows,
361+ CountableDims cols rows
358362 ) => ((Int, Int) -> e) -> Matrix e cols rows
359−matrixBuilder f =
363+matrixBuilder' f =
360364 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
361365 r = fromInteger $ natVal (Proxy :: Proxy (Count rows))
362366 positions = [(a, b) | a <- [0 .. (r - 1)], b <- [0 .. (c - 1)]]
363367 in fromLists . map (map f) . groupBy (\(x, _) (w, _) -> x == w) $ positions
364368
369+-- | Matrix builder function. Constructs a matrix provided with
370+-- a construction function that operates with arbitrary types.
371+matrixBuilder ::
372+ forall e a b.
373+ ( FLN a b,
374+ Enum a,
375+ Enum b,
376+ Bounded a,
377+ Bounded b,
378+ Eq a,
379+ Countable b
380+ ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
381+matrixBuilder f =
382+ let r = fromInteger $ natVal (Proxy :: Proxy (Count b))
383+ positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
384+ in fromLists . map (map f) . transpose . buildList r $ positions
385+ where
386+ buildList _ [] = []
387+ buildList r l = take r l : buildList r (drop r l)
388+
365389-- | Constructs a column vector matrix
366−col :: (FromLists e () rows) => [e] -> Matrix e () rows
390+col :: (FL () rows) => [e] -> Matrix e () rows
367391col = fromLists . map (: [])
368392
369393-- | Constructs a row vector matrix
370−row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
394+row :: (FL cols ()) => [e] -> Matrix e cols ()
371395row = fromLists . (: [])
372396
373397-- | Lifts functions to matrices with arbitrary dimensions.
@@ -377,8 +401,8 @@ row = fromLists . (: [])
377401fromF' ::
378402 forall a b cols rows e.
379403 ( Liftable e a b,
380− CountableDimensions cols rows,
381− FromLists e rows cols
404+ CountableDims cols rows,
405+ FL rows cols
382406 ) =>
383407 (a -> b) ->
384408 Matrix e cols rows
@@ -406,35 +430,17 @@ fromF' f =
406430fromF ::
407431 forall a b e.
408432 ( Liftable e a b,
409− CountableDimensionsN a b,
410− FromListsN e b a
433+ CountableDimsN a b,
434+ FLN b a
411435 ) =>
412436 (a -> b) ->
413437 Matrix e (Normalize a) (Normalize b)
414−fromF f =
415− let minA = minBound @a
416− maxA = maxBound @a
417− minB = minBound @b
418− maxB = maxBound @b
419− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
420− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
421− elementsA = take ccols [minA .. maxA]
422− elementsB = take rrows [minB .. maxB]
423− combinations = (,) <$> elementsA <*> elementsB
424− combAp = map snd . sort . map (\(a, b) -> if f a == b
425− then ((fromEnum a, fromEnum b), 1)
426− else ((fromEnum a, fromEnum b), 0)) $ combinations
427− mList = buildList combAp rrows
428− in tr $ fromLists mList
429− where
430− buildList [] _ = []
431− buildList l r = take r l : buildList (drop r l) r
438+fromF = fromF'
432439
433440-- Conversion
434441
435442-- | Converts a matrix to a list of lists of elements.
436443toLists :: Matrix e cols rows -> [[e]]
437−toLists Empty = []
438444toLists (One e) = [[e]]
439445toLists (Fork l r) = toLists l ++ toLists r
440446toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
@@ -446,28 +452,28 @@ toList = concat . toLists
446452-- Zeros Matrix
447453
448454-- | The zero matrix. A matrix wholly filled with zeros.
449−zeros :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
450−zeros = matrixBuilder (const 0)
455+zeros :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
456+zeros = matrixBuilder' (const 0)
451457
452458-- Ones Matrix
453459
454460-- | The ones matrix. A matrix wholly filled with ones.
455461--
456462-- Also known as T (Top) matrix.
457−ones :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
458−ones = matrixBuilder (const 1)
463+ones :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
464+ones = matrixBuilder' (const 1)
459465
460466-- Const Matrix
461467
462468-- | The constant matrix constructor. A matrix wholly filled with a given
463469-- value.
464−constant :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => e -> Matrix e cols rows
465−constant e = matrixBuilder (const e)
470+constant :: (Num e, FL cols rows, CountableDims cols rows) => e -> Matrix e cols rows
471+constant e = matrixBuilder' (const e)
466472
467473-- Bang Matrix
468474
469475-- | The T (Top) row vector matrix.
470−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 ()
471477bang =
472478 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
473479 in fromLists [take c [1, 1 ..]]
@@ -475,8 +481,8 @@ bang =
475481-- iden Matrix
476482
477483-- | iden matrix.
478−iden :: (Num e, FromLists e cols cols, Countable cols) => Matrix e cols cols
479−iden = matrixBuilder (bool 0 1 . uncurry (==))
484+iden :: forall e cols . (Num e, FL cols cols, Countable cols) => Matrix e cols cols
485+iden = matrixBuilder' (bool 0 1 . uncurry (==))
480486{-# NOINLINE iden #-}
481487
482488-- Matrix composition (MMM)
@@ -486,65 +492,90 @@ iden = matrixBuilder (bool 0 1 . uncurry (==))
486492-- This definition takes advantage of divide-and-conquer and fusion laws
487493-- from LAoP.
488494comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
489−comp Empty Empty = Empty
490495comp (One a) (One b) = One (a * b)
491496comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
492497comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
493498comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
494499{-# NOINLINE comp #-}
495−{-# RULES
500+{-# RULES
496501 "comp/iden1" forall m. comp m iden = m ;
497502 "comp/iden2" forall m. comp iden m = m
498503#-}
499504
505+-- Scalar multiplication of matrices
506+
507+infixl 7 .|
508+-- | Scalar multiplication of matrices.
509+(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
510+(.|) e (One a) = One (e * a)
511+(.|) e (Join a b) = Join (e .| a) (e .| b)
512+(.|) e (Fork a b) = Fork (e .| a) (e .| b)
513+
514+-- Scalar division of matrices
515+
516+infixl 7 ./
517+-- | Scalar multiplication of matrices.
518+(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
519+(./) (One a) e = One (a / e)
520+(./) (Join a b) e = Join (a ./ e) (b ./ e)
521+(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
522+
500523-- Projections
501524
502525-- | Biproduct first component projection
503−p1 :: forall e m n. (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e (Either m n) m
504−p1 =
505− let iden = iden :: Matrix e m m
506− zero = zeros :: Matrix e n m
507− in join iden zero
526+p1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e (Either m n) m
527+p1 = join id zeros
508528
509529-- | Biproduct second component projection
510−p2 :: forall e m n. (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e (Either m n) n
511−p2 =
512− let iden = iden :: Matrix e n n
513− zero = zeros :: Matrix e m n
514− in join zero iden
530+p2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e (Either m n) n
531+p2 = join zeros id
515532
516533-- Injections
517534
518535-- | Biproduct first component injection
519−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)
520537i1 = tr p1
521538
522539-- | Biproduct second component injection
523−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)
524541i2 = tr p2
525542
526543-- Dimensions
527544
528545-- | Obtain the number of rows.
529546--
530−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
531−-- dimensions in constant time.
532−--
533−-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
534−-- 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''.
535550rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
536551rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
537552
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+
538562-- | Obtain the number of columns.
539−--
540−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
541−-- dimensions in constant time.
542563--
543−-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
544−-- 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''.
545567columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
546568columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
547569
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+
548579-- Coproduct Bifunctor
549580
550581infixl 5 -|-
@@ -553,11 +584,11 @@ infixl 5 -|-
553584(-|-) ::
554585 forall e n k m j.
555586 ( Num e,
556− CountableDimensions j k,
557− FromLists e k k,
558− FromLists e j k,
559− FromLists e k j,
560− FromLists e j j
587+ CountableDims j k,
588+ FL k k,
589+ FL j k,
590+ FL k j,
591+ FL j j
561592 ) =>
562593 Matrix e n k ->
563594 Matrix e m j ->
@@ -570,11 +601,11 @@ infixl 5 -|-
570601fstM ::
571602 forall e m k .
572603 ( Num e,
573− CountableDimensions k m,
574− FromLists e (Normalize (m, k)) m,
604+ CountableDims k m,
605+ FL (Normalize (m, k)) m,
575606 CountableN (m, k)
576607 ) => Matrix e (Normalize (m, k)) m
577−fstM = matrixBuilder f
608+fstM = matrixBuilder' f
578609 where
579610 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
580611 f (x, y)
@@ -585,11 +616,11 @@ fstM = matrixBuilder f
585616sndM ::
586617 forall e m k .
587618 ( Num e,
588− CountableDimensions k m,
589− FromLists e (Normalize (m, k)) k,
619+ CountableDims k m,
620+ FL (Normalize (m, k)) k,
590621 CountableN (m, k)
591622 ) => Matrix e (Normalize (m, k)) k
592−sndM = matrixBuilder f
623+sndM = matrixBuilder' f
593624 where
594625 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
595626 f (x, y)
@@ -599,7 +630,7 @@ sndM = matrixBuilder f
599630-- | Khatri Rao Matrix product also known as matrix pairing.
600631--
601632-- NOTE: That this is not a true categorical product, see for instance:
602−--
633+--
603634-- @
604635-- | fstM . kr a b == a
605636-- kr a b ==> |
@@ -610,15 +641,15 @@ sndM = matrixBuilder f
610641kr ::
611642 forall e cols a b.
612643 ( Num e,
613− CountableDimensions a b,
644+ CountableDims a b,
614645 CountableN (a, b),
615− FromLists e (Normalize (a, b)) a,
616− FromLists e (Normalize (a, b)) b
646+ FL (Normalize (a, b)) a,
647+ FL (Normalize (a, b)) b
617648 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
618649kr a b =
619650 let fstM' = fstM @e @a @b
620651 sndM' = sndM @e @a @b
621− in tr fstM' . a * tr sndM' . b
652+ in (tr fstM' . a) * (tr sndM' . b)
622653
623654-- Product Bifunctor (Kronecker)
624655
@@ -628,14 +659,14 @@ infixl 4 ><
628659(><) ::
629660 forall e m p n q.
630661 ( Num e,
631− CountableDimensions m n,
632− CountableDimensions p q,
633− CountableDimensionsN (m, n) (p, q),
634− FromLists e (Normalize (m, n)) m,
635− FromLists e (Normalize (m, n)) n,
636− FromLists e (Normalize (p, q)) p,
637− FromLists e (Normalize (p, q)) q
638− )
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+ )
639670 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
640671(><) a b =
641672 let fstM' = fstM @e @m @n
@@ -653,7 +684,6 @@ infixl 4 ><
653684-- @
654685abideJF :: Matrix e cols rows -> Matrix e cols rows
655686abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
656−abideJF Empty = Empty
657687abideJF (One e) = One e
658688abideJF (Join a b) = Join (abideJF a) (abideJF b)
659689abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
@@ -667,7 +697,6 @@ abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
667697-- @
668698abideFJ :: Matrix e cols rows -> Matrix e cols rows
669699abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
670−abideFJ Empty = Empty
671700abideFJ (One e) = One e
672701abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
673702abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
@@ -676,7 +705,6 @@ abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
676705
677706-- | Matrix transposition.
678707tr :: Matrix e cols rows -> Matrix e rows cols
679−tr Empty = Empty
680708tr (One e) = One e
681709tr (Join a b) = Fork (tr a) (tr b)
682710tr (Fork a b) = Join (tr a) (tr b)
@@ -685,32 +713,32 @@ tr (Fork a b) = Join (tr a) (tr b)
685713
686714-- | Selective functors 'select' operator equivalent inspired by the
687715-- ArrowMonad solution presented in the paper.
688−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
689717select (Fork a b) y = y . a + b -- Divide-and-conquer law
690718select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
691−select m y = join y iden . m
719+select m y = join y id . m
692720
693721branch ::
694722 ( Num e,
695− CountableDimensions a b,
696− CountableDimensions c (Either b c),
697− FromLists e c b,
698− FromLists e a b,
699− FromLists e a a,
700− FromLists e b b,
701− FromLists e c c,
702− FromLists e b a,
703− FromLists e b c,
704− FromLists e (Either b c) b,
705− 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
706734 )
707735 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
708736branch x l r = f x `select` g l `select` r
709737 where
710− 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)
711739 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
712740 f m = fork (tr i1) (i1 . tr i2) . m
713− 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)
714742 g m = i2 . m
715743
716744-- McCarthy's Conditional
@@ -719,9 +747,9 @@ branch x l r = f x `select` g l `select` r
719747cond ::
720748 ( Trivial cols,
721749 Countable cols,
722− FromLists e () cols,
723− FromLists e cols (),
724− FromLists e cols cols,
750+ FL () cols,
751+ FL cols (),
752+ FL cols cols,
725753 Bounded a,
726754 Enum a,
727755 Num e,
@@ -734,9 +762,9 @@ cond p f g = join f g . grd p
734762grd ::
735763 ( Trivial q,
736764 Countable q,
737− FromLists e () q,
738− FromLists e q (),
739− FromLists e q q,
765+ FL () q,
766+ FL q (),
767+ FL q q,
740768 Bounded a,
741769 Enum a,
742770 Num e,
@@ -750,14 +778,14 @@ corr ::
750778 forall e a q .
751779 ( Trivial q,
752780 Countable q,
753− FromLists e () q,
754− FromLists e q (),
755− FromLists e q q,
781+ FL () q,
782+ FL q (),
783+ FL q q,
756784 Liftable e a Bool
757785 )
758786 => (a -> Bool) -> Matrix e q q
759787corr p = let f = fromF' p :: Matrix e q ()
760− in kr f (iden :: Matrix e q q)
788+ in kr f (id :: Matrix e q q)
761789
762790-- Pretty print
763791
@@ -781,7 +809,7 @@ prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
781809 fill str = replicate (widest - length str - 2) ' ' ++ str
782810
783811-- | Matrix pretty printer
784−pretty :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> String
812+pretty :: (CountableDims cols rows, Show e) => Matrix e cols rows -> String
785813pretty m = concat
786814 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
787815 , unlines
@@ -810,12 +838,11 @@ pretty m = concat
810838 (safeGet i j m)
811839
812840-- | Matrix pretty printer
813−prettyPrint :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> IO ()
841+prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
814842prettyPrint = putStrLn . pretty
815843
816844-- | Zip two matrices with a given binary function
817845zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
818−zipWithM _ Empty Empty = Empty
819846zipWithM f (One a) (One b) = One (f a b)
820847zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
821848zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
@@ -840,14 +867,12 @@ fromBool False = nat 0
840867
841868-- | Relational negation
842869negateM :: Relation cols rows -> Relation cols rows
843−negateM Empty = Empty
844870negateM (One (Nat p)) = One (Nat (negate p))
845871negateM (Join a b) = Join (negateM a) (negateM b)
846872negateM (Fork a b) = Fork (negateM a) (negateM b)
847873
848874-- | Relational addition
849875orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
850−orM Empty Empty = Empty
851876orM (One a) (One b) = One (fromBool (toBool a || toBool b))
852877orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
853878orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
@@ -856,7 +881,6 @@ orM x@(Join _ _) y@(Fork _ _) = orM (abideJF x) y
856881
857882-- | Relational multiplication
858883andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
859−andM Empty Empty = Empty
860884andM (One a) (One b) = One (fromBool (toBool a && toBool b))
861885andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
862886andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
@@ -865,7 +889,6 @@ andM x@(Join _ _) y@(Fork _ _) = andM (abideJF x) y
865889
866890-- | Relational subtraction
867891subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
868−subM Empty Empty = Empty
869892subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
870893subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
871894subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
@@ -874,7 +897,6 @@ subM x@(Join _ _) y@(Fork _ _) = subM (abideJF x) y
874897
875898-- | Matrix relational composition.
876899compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
877−compRel Empty Empty = Empty
878900compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
879901compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
880902compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
@@ -882,7 +904,6 @@ compRel c (Join a b) = Join (compRel c a) (compRel c b) -- Join fusion
882904
883905-- | Matrix relational right division
884906divR :: Relation b c -> Relation b a -> Relation a c
885−divR Empty Empty = Empty
886907divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
887908divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
888909divR (Fork a b) c = Fork (divR a c) (divR b c)
@@ -905,58 +926,24 @@ divS s r = divL r s `intersection` divR (tr r) (tr s)
905926fromFRel' ::
906927 forall a b cols rows.
907928 ( Liftable Boolean a b,
908− CountableDimensions cols rows,
909− FromLists Boolean rows cols
929+ CountableDims cols rows,
930+ FL rows cols
910931 ) =>
911932 (a -> b) ->
912933 Relation cols rows
913−fromFRel' f =
914− let minA = minBound @a
915− maxA = maxBound @a
916− minB = minBound @b
917− maxB = maxBound @b
918− ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
919− rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
920− elementsA = take ccols [minA .. maxA]
921− elementsB = take rrows [minB .. maxB]
922− combinations = (,) <$> elementsA <*> elementsB
923− combAp = map snd . sort . map (\(a, b) -> if f a == b
924− then ((fromEnum a, fromEnum b), nat 1)
925− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
926− mList = buildList combAp rrows
927− in tr $ fromLists mList
928− where
929− buildList [] _ = []
930− buildList l r = take r l : buildList (drop r l) r
934+fromFRel' = fromF'
931935
932936-- | Lifts functions to relations with dimensions matching @a@ and @b@
933937-- cardinality's.
934938fromFRel ::
935939 forall a b.
936940 ( Liftable Boolean a b,
937− CountableDimensionsN a b,
938− FromLists Boolean (Normalize b) (Normalize a)
941+ CountableDimsN a b,
942+ FLN b a
939943 ) =>
940944 (a -> b) ->
941945 Relation (Normalize a) (Normalize b)
942−fromFRel f =
943− let minA = minBound @a
944− maxA = maxBound @a
945− minB = minBound @b
946− maxB = maxBound @b
947− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
948− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
949− elementsA = take ccols [minA .. maxA]
950− elementsB = take rrows [minB .. maxB]
951− combinations = (,) <$> elementsA <*> elementsB
952− combAp = map snd . sort . map (\(a, b) -> if f a == b
953− then ((fromEnum a, fromEnum b), nat 1)
954− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
955− mList = buildList combAp rrows
956− in tr $ fromLists mList
957− where
958− buildList [] _ = []
959− buildList l r = take r l : buildList (drop r l) r
946+fromFRel = fromFRel'
960947
961948-- | Lifts a relation function to a Boolean Matrix
962949toRel ::
@@ -966,17 +953,17 @@ toRel ::
966953 Enum a,
967954 Enum b,
968955 Eq b,
969− CountableDimensionsN a b,
970− FromListsN Boolean b a
971− )
956+ CountableDims a b,
957+ FLN b a
958+ )
972959 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
973960toRel f =
974961 let minA = minBound @a
975962 maxA = maxBound @a
976963 minB = minBound @b
977964 maxB = maxBound @b
978− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
979− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
965+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
966+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
980967 elementsA = take ccols [minA .. maxA]
981968 elementsB = take rrows [minB .. maxB]
982969 combinations = (,) <$> elementsA <*> elementsB