@@ -30,7 +30,7 @@
30-- motivation behind the library, the underlying theory, and implementation details.
30-- motivation behind the library, the underlying theory, and implementation details.
32-- This module offers many of the combinators mentioned in the work of
32-- This module offers many of the combinators mentioned in the work of
33−-- Macedo (2012) and Oliveira (2012).
33+-- Macedo (2012) and Oliveira (2012).
35-- This is an Internal module and it is no supposed to be imported.
35-- This is an Internal module and it is no supposed to be imported.
@@ -43,14 +43,23 @@ module LAoP.Matrix.Internal
44 -- There exists two type families that make it easier to write
44 -- There exists two type families that make it easier to write
45 -- matrix dimensions: 'FromNat' and 'Count'. This approach
45 -- matrix dimensions: 'FromNat' and 'Count'. This approach
46− -- leads to a very straightforward implementation
46+ -- leads to a very straightforward implementation
47− -- of LAoP combinators.
47+ -- of LAoP combinators.
49 -- * Type safe matrix representation
49 -- * Type safe matrix representation
50 Matrix (..),
50 Matrix (..),
52+ -- * Constraint type aliases
52 -- * Primitives
62 -- * Primitives
@@ -77,7 +86,9 @@ module LAoP.Matrix.Internal
78 -- ** Get dimensions
87 -- ** Get dimensions
82 -- ** Matrix Transposition
93 -- ** Matrix Transposition
@@ -165,6 +176,7 @@ import Data.Kind
165import Data.List
176import Data.List
166import Data.Maybe
177import Data.Maybe
167import Data.Proxy
178import Data.Proxy
168import Data.Void
180import Data.Void
169import GHC.TypeLits
181import GHC.TypeLits
170import Data.Type.Equality
182import Data.Type.Equality
@@ -175,7 +187,6 @@ import qualified Prelude (id, (.))
176-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
188-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
177data Matrix e cols rows where
189data Matrix e cols rows where
178− Empty :: Matrix e Void Void
179 One :: e -> Matrix e () ()
190 One :: e -> Matrix e () ()
180 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
191 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
181 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
192 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
@@ -205,7 +216,6 @@ type family Count (d :: Type) :: Nat where
206-- Thanks to Li-Yao Xia this type family is super fast.
217-- Thanks to Li-Yao Xia this type family is super fast.
207type family FromNat (n :: Nat) :: Type where
218type family FromNat (n :: Nat) :: Type where
209 FromNat 1 = ()
219 FromNat 1 = ()
210 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
220 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
@@ -222,27 +232,26 @@ type family Normalize (d :: Type) :: Type where
222-- | Constraint type synonyms to keep the type signatures less convoluted
232-- | Constraint type synonyms to keep the type signatures less convoluted
223type Countable a = KnownNat (Count a)
233type Countable a = KnownNat (Count a)
224type CountableN a = KnownNat (Count (Normalize a))
234type CountableN a = KnownNat (Count (Normalize a))
225−type CountableDimensions a b = (Countable a, Countable b)
235+type CountableDims a b = (Countable a, Countable b)
226−type CountableDimensionsN a b = (CountableN a, CountableN b)
236+type CountableDimsN a b = (CountableN a, CountableN b)
237+type FL a b = FromLists a b
227−type FromListsN e a b = FromLists e (Normalize a) (Normalize b)
238+type FLN a b = FromLists (Normalize a) (Normalize b)
228type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
239type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
229type Trivial a = FromNat (Count a) ~ a
240type Trivial a = FromNat (Count a) ~ a
231-- | It is possible to implement a constrained version of the category type
242-- | It is possible to implement a constrained version of the category type
233instance (Num e) => Category (Matrix e) where
244instance (Num e) => Category (Matrix e) where
234− type Object (Matrix e) a = (FromLists e a a, Countable a)
245+ type Object (Matrix e) a = (FL a a, Countable a)
235− id = iden
246+ id = iden
236 (.) = comp
247 (.) = comp
238instance NFData e => NFData (Matrix e cols rows) where
249instance NFData e => NFData (Matrix e cols rows) where
240 rnf (One e) = rnf e
250 rnf (One e) = rnf e
241 rnf (Join a b) = rnf a `seq` rnf b
251 rnf (Join a b) = rnf a `seq` rnf b
242 rnf (Fork a b) = rnf a `seq` rnf b
252 rnf (Fork a b) = rnf a `seq` rnf b
244instance Eq e => Eq (Matrix e cols rows) where
254instance Eq e => Eq (Matrix e cols rows) where
245− Empty == Empty = True
246 (One a) == (One b) = a == b
255 (One a) == (One b) = a == b
247 (Join a b) == (Join c d) = a == c && b == d
256 (Join a b) == (Join c d) = a == c && b == d
248 (Fork a b) == (Fork c d) = a == c && b == d
257 (Fork a b) == (Fork c d) = a == c && b == d
@@ -250,25 +259,21 @@ instance Eq e => Eq (Matrix e cols rows) where
250 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
259 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
252instance Num e => Num (Matrix e cols rows) where
261instance Num e => Num (Matrix e cols rows) where
254 a + b = zipWithM (+) a b
262 a + b = zipWithM (+) a b
256 a - b = zipWithM (-) a b
264 a - b = zipWithM (-) a b
258 a * b = zipWithM (*) a b
266 a * b = zipWithM (*) a b
261 abs (One a) = One (abs a)
268 abs (One a) = One (abs a)
262 abs (Join a b) = Join (abs a) (abs b)
269 abs (Join a b) = Join (abs a) (abs b)
263 abs (Fork a b) = Fork (abs a) (abs b)
270 abs (Fork a b) = Fork (abs a) (abs b)
265− signum Empty = Empty
266 signum (One a) = One (signum a)
272 signum (One a) = One (signum a)
267 signum (Join a b) = Join (signum a) (signum b)
273 signum (Join a b) = Join (signum a) (signum b)
268 signum (Fork a b) = Fork (signum a) (signum b)
274 signum (Fork a b) = Fork (signum a) (signum b)
270instance Ord e => Ord (Matrix e cols rows) where
276instance Ord e => Ord (Matrix e cols rows) where
271− Empty <= Empty = True
272 (One a) <= (One b) = a <= b
277 (One a) <= (One b) = a <= b
273 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
278 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
274 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
279 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
@@ -277,10 +282,6 @@ instance Ord e => Ord (Matrix e cols rows) where
278-- Primitives
283-- Primitives
280−-- | Empty matrix constructor
281−empty :: Matrix e Void Void
284-- | Unit matrix constructor
285-- | Unit matrix constructor
285one :: e -> Matrix e () ()
286one :: e -> Matrix e () ()
@@ -311,40 +312,39 @@ infixl 2 ===
312-- Given that it is not possible to branch on types at the term level type
313-- Given that it is not possible to branch on types at the term level type
313-- classes are needed very much like an inductive definition but on types.
314-- classes are needed very much like an inductive definition but on types.
314−class FromLists e cols rows where
315+class FromLists cols rows where
315 -- | Build a matrix out of a list of list of elements. Throws a runtime
316 -- | Build a matrix out of a list of list of elements. Throws a runtime
316 -- error if the dimensions do not match.
317 -- error if the dimensions do not match.
317 fromLists :: [[e]] -> Matrix e cols rows
318 fromLists :: [[e]] -> Matrix e cols rows
319−instance FromLists e Void Void where
320+instance FromLists () () where
320− fromLists [] = Empty
321− fromLists _ = error "Wrong dimensions"
323−instance {-# OVERLAPPING #-} FromLists e () () where
324 fromLists [[e]] = One e
321 fromLists [[e]] = One e
325 fromLists _ = error "Wrong dimensions"
322 fromLists _ = error "Wrong dimensions"
327−instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
324+instance (FromLists cols ()) => FromLists (Either () cols) () where
328 fromLists [h : t] = Join (One h) (fromLists [t])
325 fromLists [h : t] = Join (One h) (fromLists [t])
329 fromLists _ = error "Wrong dimensions"
326 fromLists _ = error "Wrong dimensions"
328+instance {-# OVERLAPPABLE #-}
331−instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), Countable a) => FromLists e (Either a b) () where
329+ (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
332 fromLists [l] =
330 fromLists [l] =
333 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
331 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
334 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
332 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
335 fromLists _ = error "Wrong dimensions"
333 fromLists _ = error "Wrong dimensions"
337−instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
335+instance (FromLists () rows) => FromLists () (Either () rows) where
338 fromLists ([h] : t) = Fork (One h) (fromLists t)
336 fromLists ([h] : t) = Fork (One h) (fromLists t)
339 fromLists _ = error "Wrong dimensions"
337 fromLists _ = error "Wrong dimensions"
339+instance {-# OVERLAPPABLE #-}
341−instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) where
340+ (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
342− fromLists l@([_] : _) =
341+ fromLists l@([_] : _) =
343 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
342 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
344 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
343 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
345 fromLists _ = error "Wrong dimensions"
344 fromLists _ = error "Wrong dimensions"
347−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
348 fromLists l@(h : t) =
348 fromLists l@(h : t) =
349 let lh = length h
349 let lh = length h
350 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
350 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
@@ -357,8 +357,8 @@ instance {-# OVERLAPPABLE #-} (FromLists e (Either a b) c, FromLists e (Either a
357-- a construction function that operates with indices.
357-- a construction function that operates with indices.
358matrixBuilder' ::
358matrixBuilder' ::
359 forall e cols rows.
359 forall e cols rows.
360− ( FromLists e cols rows,
360+ ( FL cols rows,
361− CountableDimensions cols rows
361+ CountableDims cols rows
362 ) => ((Int, Int) -> e) -> Matrix e cols rows
362 ) => ((Int, Int) -> e) -> Matrix e cols rows
363matrixBuilder' f =
363matrixBuilder' f =
364 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
364 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
@@ -370,17 +370,16 @@ matrixBuilder' f =
370-- a construction function that operates with arbitrary types.
370-- a construction function that operates with arbitrary types.
371matrixBuilder ::
371matrixBuilder ::
372 forall e a b.
372 forall e a b.
373− ( FromListsN e a b,
373+ ( FLN a b,
377 Bounded a,
376 Bounded a,
378 Bounded b,
377 Bounded b,
380− CountableDimensionsN a b
379+ Countable b
381 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
380 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
382matrixBuilder f =
381matrixBuilder f =
383− let r = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
382+ let r = fromInteger $ natVal (Proxy :: Proxy (Count b))
384 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
383 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
385 in fromLists . map (map f) . transpose . buildList r $ positions
384 in fromLists . map (map f) . transpose . buildList r $ positions
@@ -388,11 +387,11 @@ matrixBuilder f =
388 buildList r l = take r l : buildList r (drop r l)
387 buildList r l = take r l : buildList r (drop r l)
390-- | Constructs a column vector matrix
389-- | Constructs a column vector matrix
391−col :: (FromLists e () rows) => [e] -> Matrix e () rows
390+col :: (FL () rows) => [e] -> Matrix e () rows
392col = fromLists . map (: [])
391col = fromLists . map (: [])
394-- | Constructs a row vector matrix
393-- | Constructs a row vector matrix
395−row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
394+row :: (FL cols ()) => [e] -> Matrix e cols ()
396row = fromLists . (: [])
395row = fromLists . (: [])
398-- | Lifts functions to matrices with arbitrary dimensions.
397-- | Lifts functions to matrices with arbitrary dimensions.
@@ -402,8 +401,8 @@ row = fromLists . (: [])
403 forall a b cols rows e.
402 forall a b cols rows e.
404 ( Liftable e a b,
403 ( Liftable e a b,
405− CountableDimensions cols rows,
404+ CountableDims cols rows,
406− FromLists e rows cols
405+ FL rows cols
408 (a -> b) ->
407 (a -> b) ->
409 Matrix e cols rows
408 Matrix e cols rows
@@ -431,35 +430,17 @@ fromF' f =
432 forall a b e.
431 forall a b e.
433 ( Liftable e a b,
432 ( Liftable e a b,
434− CountableDimensionsN a b,
433+ CountableDimsN a b,
435− FromListsN e b a
434+ FLN b a
437 (a -> b) ->
436 (a -> b) ->
438 Matrix e (Normalize a) (Normalize b)
437 Matrix e (Normalize a) (Normalize b)
439−fromF f =
438+fromF = fromF'
440− let minA = minBound @a
444− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
445− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
446− elementsA = take ccols [minA .. maxA]
447− elementsB = take rrows [minB .. maxB]
448− combinations = (,) <$> elementsA <*> elementsB
449− combAp = map snd . sort . map (\(a, b) -> if f a == b
450− then ((fromEnum a, fromEnum b), 1)
451− else ((fromEnum a, fromEnum b), 0)) $ combinations
452− mList = buildList combAp rrows
453− in tr $ fromLists mList
456− buildList l r = take r l : buildList (drop r l) r
458-- Conversion
440-- Conversion
460-- | Converts a matrix to a list of lists of elements.
442-- | Converts a matrix to a list of lists of elements.
461toLists :: Matrix e cols rows -> [[e]]
443toLists :: Matrix e cols rows -> [[e]]
463toLists (One e) = [[e]]
444toLists (One e) = [[e]]
464toLists (Fork l r) = toLists l ++ toLists r
445toLists (Fork l r) = toLists l ++ toLists r
465toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
446toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
@@ -471,7 +452,7 @@ toList = concat . toLists
471-- Zeros Matrix
452-- Zeros Matrix
473-- | The zero matrix. A matrix wholly filled with zeros.
454-- | The zero matrix. A matrix wholly filled with zeros.
474−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
475zeros = matrixBuilder' (const 0)
456zeros = matrixBuilder' (const 0)
477-- Ones Matrix
458-- Ones Matrix
@@ -479,20 +460,20 @@ zeros = matrixBuilder' (const 0)
479-- | The ones matrix. A matrix wholly filled with ones.
460-- | The ones matrix. A matrix wholly filled with ones.
481-- Also known as T (Top) matrix.
462-- Also known as T (Top) matrix.
482−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
483ones = matrixBuilder' (const 1)
464ones = matrixBuilder' (const 1)
485-- Const Matrix
466-- Const Matrix
487-- | The constant matrix constructor. A matrix wholly filled with a given
468-- | The constant matrix constructor. A matrix wholly filled with a given
489−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
490constant e = matrixBuilder' (const e)
471constant e = matrixBuilder' (const e)
492-- Bang Matrix
473-- Bang Matrix
494-- | The T (Top) row vector matrix.
475-- | The T (Top) row vector matrix.
495−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 ()
497 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
478 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
498 in fromLists [take c [1, 1 ..]]
479 in fromLists [take c [1, 1 ..]]
@@ -500,7 +481,7 @@ bang =
500-- iden Matrix
481-- iden Matrix
502-- | iden matrix.
483-- | iden matrix.
503−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
504iden = matrixBuilder' (bool 0 1 . uncurry (==))
485iden = matrixBuilder' (bool 0 1 . uncurry (==))
505{-# NOINLINE iden #-}
486{-# NOINLINE iden #-}
@@ -511,13 +492,12 @@ iden = matrixBuilder' (bool 0 1 . uncurry (==))
511-- This definition takes advantage of divide-and-conquer and fusion laws
492-- This definition takes advantage of divide-and-conquer and fusion laws
512-- from LAoP.
493-- from LAoP.
513comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
494comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
514−comp Empty Empty = Empty
515comp (One a) (One b) = One (a * b)
495comp (One a) (One b) = One (a * b)
516comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
496comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
517comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
497comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
518comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
498comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
519{-# NOINLINE comp #-}
499{-# NOINLINE comp #-}
520−{-# RULES
500+{-# RULES
521 "comp/iden1" forall m. comp m iden = m ;
501 "comp/iden1" forall m. comp m iden = m ;
522 "comp/iden2" forall m. comp iden m = m
502 "comp/iden2" forall m. comp iden m = m
@@ -527,7 +507,6 @@ comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
527infixl 7 .|
507infixl 7 .|
528-- | Scalar multiplication of matrices.
508-- | Scalar multiplication of matrices.
529(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
509(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
531(.|) e (One a) = One (e * a)
510(.|) e (One a) = One (e * a)
532(.|) e (Join a b) = Join (e .| a) (e .| b)
511(.|) e (Join a b) = Join (e .| a) (e .| b)
533(.|) e (Fork a b) = Fork (e .| a) (e .| b)
512(.|) e (Fork a b) = Fork (e .| a) (e .| b)
@@ -537,7 +516,6 @@ infixl 7 .|
537infixl 7 ./
516infixl 7 ./
538-- | Scalar multiplication of matrices.
517-- | Scalar multiplication of matrices.
539(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
518(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
541(./) (One a) e = One (a / e)
519(./) (One a) e = One (a / e)
542(./) (Join a b) e = Join (a ./ e) (b ./ e)
520(./) (Join a b) e = Join (a ./ e) (b ./ e)
543(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
521(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
@@ -545,45 +523,59 @@ infixl 7 ./
545-- Projections
523-- Projections
547-- | Biproduct first component projection
525-- | Biproduct first component projection
548−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
549p1 = join id zeros
527p1 = join id zeros
551-- | Biproduct second component projection
529-- | Biproduct second component projection
552−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
553p2 = join zeros id
531p2 = join zeros id
555-- Injections
533-- Injections
557-- | Biproduct first component injection
535-- | Biproduct first component injection
558−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)
559i1 = tr p1
537i1 = tr p1
561-- | Biproduct second component injection
539-- | Biproduct second component injection
562−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)
563i2 = tr p2
541i2 = tr p2
565-- Dimensions
543-- Dimensions
567-- | Obtain the number of rows.
545-- | Obtain the number of rows.
569−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
547+-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
570−-- dimensions in constant time.
548+-- dimensions in constant time. For a version that doesn't require the
571−--
549+-- constraint see 'rows''.
572−-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
573−-- exchange for performance.
574rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
550rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
575rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
551rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
553+-- | Obtain the number of rows in an inefficient manner, but without any
556+-- For a more efficient version see 'rows'.
557+rows' :: Matrix e cols rows -> Int
559+rows' (Join lhs _) = rows' lhs
560+rows' (Fork top bottom) = rows' top + rows' bottom
577-- | Obtain the number of columns.
562-- | Obtain the number of columns.
579−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
580−-- dimensions in constant time.
582−-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
564+-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
583−-- exchange for performance.
565+-- dimensions in constant time. For a version that doesn't require the
566+-- constraint see 'columns''.
584columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
567columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
585columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
568columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
570+-- | Obtain the number of columns in an inefficient manner, but without any
573+-- For a more efficient version see 'columns'.
574+columns' :: Matrix e cols rows -> Int
576+columns' (Join lhs rhs) = columns' lhs + columns' rhs
577+columns' (Fork top _) = columns' top
587-- Coproduct Bifunctor
579-- Coproduct Bifunctor
589infixl 5 -|-
581infixl 5 -|-
@@ -592,11 +584,11 @@ infixl 5 -|-
593 forall e n k m j.
585 forall e n k m j.
595− CountableDimensions j k,
587+ CountableDims j k,
596− FromLists e k k,
588+ FL k k,
597− FromLists e j k,
589+ FL j k,
598− FromLists e k j,
590+ FL k j,
599− FromLists e j j
591+ FL j j
601 Matrix e n k ->
593 Matrix e n k ->
602 Matrix e m j ->
594 Matrix e m j ->
@@ -609,8 +601,8 @@ infixl 5 -|-
610 forall e m k .
602 forall e m k .
612− CountableDimensions k m,
604+ CountableDims k m,
613− FromLists e (Normalize (m, k)) m,
605+ FL (Normalize (m, k)) m,
614 CountableN (m, k)
606 CountableN (m, k)
615 ) => Matrix e (Normalize (m, k)) m
607 ) => Matrix e (Normalize (m, k)) m
616fstM = matrixBuilder' f
608fstM = matrixBuilder' f
@@ -624,8 +616,8 @@ fstM = matrixBuilder' f
625 forall e m k .
617 forall e m k .
627− CountableDimensions k m,
619+ CountableDims k m,
628− FromLists e (Normalize (m, k)) k,
620+ FL (Normalize (m, k)) k,
629 CountableN (m, k)
621 CountableN (m, k)
630 ) => Matrix e (Normalize (m, k)) k
622 ) => Matrix e (Normalize (m, k)) k
631sndM = matrixBuilder' f
623sndM = matrixBuilder' f
@@ -638,7 +630,7 @@ sndM = matrixBuilder' f
638-- | Khatri Rao Matrix product also known as matrix pairing.
630-- | Khatri Rao Matrix product also known as matrix pairing.
640-- NOTE: That this is not a true categorical product, see for instance:
632-- NOTE: That this is not a true categorical product, see for instance:
643-- | fstM . kr a b == a
635-- | fstM . kr a b == a
644-- kr a b ==> |
636-- kr a b ==> |
@@ -649,10 +641,10 @@ sndM = matrixBuilder' f
650 forall e cols a b.
642 forall e cols a b.
652− CountableDimensions a b,
644+ CountableDims a b,
653 CountableN (a, b),
645 CountableN (a, b),
654− FromLists e (Normalize (a, b)) a,
646+ FL (Normalize (a, b)) a,
655− FromLists e (Normalize (a, b)) b
647+ FL (Normalize (a, b)) b
656 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
648 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
658 let fstM' = fstM @e @a @b
650 let fstM' = fstM @e @a @b
@@ -667,14 +659,14 @@ infixl 4 ><
668 forall e m p n q.
660 forall e m p n q.
670− CountableDimensions m n,
662+ CountableDims m n,
671− CountableDimensions p q,
663+ CountableDims p q,
672− CountableDimensionsN (m, n) (p, q),
664+ CountableDimsN (m, n) (p, q),
673− FromLists e (Normalize (m, n)) m,
665+ FL (Normalize (m, n)) m,
674− FromLists e (Normalize (m, n)) n,
666+ FL (Normalize (m, n)) n,
675− FromLists e (Normalize (p, q)) p,
667+ FL (Normalize (p, q)) p,
676− FromLists e (Normalize (p, q)) q
668+ FL (Normalize (p, q)) q
678 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
670 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
679(><) a b =
671(><) a b =
680 let fstM' = fstM @e @m @n
672 let fstM' = fstM @e @m @n
@@ -692,7 +684,6 @@ infixl 4 ><
693abideJF :: Matrix e cols rows -> Matrix e cols rows
685abideJF :: Matrix e cols rows -> Matrix e cols rows
694abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
686abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
695−abideJF Empty = Empty
696abideJF (One e) = One e
687abideJF (One e) = One e
697abideJF (Join a b) = Join (abideJF a) (abideJF b)
688abideJF (Join a b) = Join (abideJF a) (abideJF b)
698abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
689abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
@@ -706,7 +697,6 @@ abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
707abideFJ :: Matrix e cols rows -> Matrix e cols rows
698abideFJ :: Matrix e cols rows -> Matrix e cols rows
708abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
699abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
709−abideFJ Empty = Empty
710abideFJ (One e) = One e
700abideFJ (One e) = One e
711abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
701abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
712abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
702abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
@@ -715,7 +705,6 @@ abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
716-- | Matrix transposition.
706-- | Matrix transposition.
717tr :: Matrix e cols rows -> Matrix e rows cols
707tr :: Matrix e cols rows -> Matrix e rows cols
719tr (One e) = One e
708tr (One e) = One e
720tr (Join a b) = Fork (tr a) (tr b)
709tr (Join a b) = Fork (tr a) (tr b)
721tr (Fork a b) = Join (tr a) (tr b)
710tr (Fork a b) = Join (tr a) (tr b)
@@ -724,32 +713,32 @@ tr (Fork a b) = Join (tr a) (tr b)
725-- | Selective functors 'select' operator equivalent inspired by the
714-- | Selective functors 'select' operator equivalent inspired by the
726-- ArrowMonad solution presented in the paper.
715-- ArrowMonad solution presented in the paper.
727−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
728select (Fork a b) y = y . a + b -- Divide-and-conquer law
717select (Fork a b) y = y . a + b -- Divide-and-conquer law
729select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
718select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
730select m y = join y id . m
719select m y = join y id . m
734− CountableDimensions a b,
723+ CountableDims a b,
735− CountableDimensions c (Either b c),
724+ CountableDims c (Either b c),
736− FromLists e c b,
725+ FL c b,
737− FromLists e a b,
726+ FL a b,
738− FromLists e a a,
727+ FL a a,
739− FromLists e b b,
728+ FL b b,
740− FromLists e c c,
729+ FL c c,
741− FromLists e b a,
730+ FL b a,
742− FromLists e b c,
731+ FL b c,
743− FromLists e (Either b c) b,
732+ FL (Either b c) b,
744− FromLists e (Either b c) c
733+ FL (Either b c) c
746 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
735 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
747branch x l r = f x `select` g l `select` r
736branch x l r = f x `select` g l `select` r
749− 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)
750 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
739 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
751 f m = fork (tr i1) (i1 . tr i2) . m
740 f m = fork (tr i1) (i1 . tr i2) . m
752− 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)
753 g m = i2 . m
742 g m = i2 . m
755-- McCarthy's Conditional
744-- McCarthy's Conditional
@@ -758,9 +747,9 @@ branch x l r = f x `select` g l `select` r
759 ( Trivial cols,
748 ( Trivial cols,
760 Countable cols,
749 Countable cols,
761− FromLists e () cols,
750+ FL () cols,
762− FromLists e cols (),
751+ FL cols (),
763− FromLists e cols cols,
752+ FL cols cols,
764 Bounded a,
753 Bounded a,
@@ -773,9 +762,9 @@ cond p f g = join f g . grd p
774 ( Trivial q,
763 ( Trivial q,
775 Countable q,
764 Countable q,
776− FromLists e () q,
765+ FL () q,
777− FromLists e q (),
766+ FL q (),
778− FromLists e q q,
767+ FL q q,
779 Bounded a,
768 Bounded a,
@@ -789,9 +778,9 @@ corr ::
789 forall e a q .
778 forall e a q .
790 ( Trivial q,
779 ( Trivial q,
791 Countable q,
780 Countable q,
792− FromLists e () q,
781+ FL () q,
793− FromLists e q (),
782+ FL q (),
794− FromLists e q q,
783+ FL q q,
795 Liftable e a Bool
784 Liftable e a Bool
797 => (a -> Bool) -> Matrix e q q
786 => (a -> Bool) -> Matrix e q q
@@ -820,7 +809,7 @@ prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
820 fill str = replicate (widest - length str - 2) ' ' ++ str
809 fill str = replicate (widest - length str - 2) ' ' ++ str
822-- | Matrix pretty printer
811-- | Matrix pretty printer
823−pretty :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> String
812+pretty :: (CountableDims cols rows, Show e) => Matrix e cols rows -> String
824pretty m = concat
813pretty m = concat
825 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
814 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
826 , unlines
815 , unlines
@@ -849,12 +838,11 @@ pretty m = concat
849 (safeGet i j m)
838 (safeGet i j m)
851-- | Matrix pretty printer
840-- | Matrix pretty printer
852−prettyPrint :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> IO ()
841+prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
853prettyPrint = putStrLn . pretty
842prettyPrint = putStrLn . pretty
855-- | Zip two matrices with a given binary function
844-- | Zip two matrices with a given binary function
856zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
845zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
857−zipWithM _ Empty Empty = Empty
858zipWithM f (One a) (One b) = One (f a b)
846zipWithM f (One a) (One b) = One (f a b)
859zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
847zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
860zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
848zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
@@ -879,14 +867,12 @@ fromBool False = nat 0
880-- | Relational negation
868-- | Relational negation
881negateM :: Relation cols rows -> Relation cols rows
869negateM :: Relation cols rows -> Relation cols rows
882−negateM Empty = Empty
883negateM (One (Nat p)) = One (Nat (negate p))
870negateM (One (Nat p)) = One (Nat (negate p))
884negateM (Join a b) = Join (negateM a) (negateM b)
871negateM (Join a b) = Join (negateM a) (negateM b)
885negateM (Fork a b) = Fork (negateM a) (negateM b)
872negateM (Fork a b) = Fork (negateM a) (negateM b)
887-- | Relational addition
874-- | Relational addition
888orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
875orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
889−orM Empty Empty = Empty
890orM (One a) (One b) = One (fromBool (toBool a || toBool b))
876orM (One a) (One b) = One (fromBool (toBool a || toBool b))
891orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
877orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
892orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
878orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
@@ -895,7 +881,6 @@ orM x@(Join _ _) y@(Fork _ _) = orM (abideJF x) y
896-- | Relational multiplication
882-- | Relational multiplication
897andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
883andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
898−andM Empty Empty = Empty
899andM (One a) (One b) = One (fromBool (toBool a && toBool b))
884andM (One a) (One b) = One (fromBool (toBool a && toBool b))
900andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
885andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
901andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
886andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
@@ -904,7 +889,6 @@ andM x@(Join _ _) y@(Fork _ _) = andM (abideJF x) y
905-- | Relational subtraction
890-- | Relational subtraction
906subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
891subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
907−subM Empty Empty = Empty
908subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
892subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
909subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
893subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
910subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
894subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
@@ -913,7 +897,6 @@ subM x@(Join _ _) y@(Fork _ _) = subM (abideJF x) y
914-- | Matrix relational composition.
898-- | Matrix relational composition.
915compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
899compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
916−compRel Empty Empty = Empty
917compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
900compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
918compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
901compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
919compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
902compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
@@ -921,7 +904,6 @@ compRel c (Join a b) = Join (compRel c a) (compRel c b) -- Join fusion
922-- | Matrix relational right division
905-- | Matrix relational right division
923divR :: Relation b c -> Relation b a -> Relation a c
906divR :: Relation b c -> Relation b a -> Relation a c
924−divR Empty Empty = Empty
925divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
907divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
926divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
908divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
927divR (Fork a b) c = Fork (divR a c) (divR b c)
909divR (Fork a b) c = Fork (divR a c) (divR b c)
@@ -944,58 +926,24 @@ divS s r = divL r s `intersection` divR (tr r) (tr s)
944fromFRel' ::
926fromFRel' ::
945 forall a b cols rows.
927 forall a b cols rows.
946 ( Liftable Boolean a b,
928 ( Liftable Boolean a b,
947− CountableDimensions cols rows,
929+ CountableDims cols rows,
948− FromLists Boolean rows cols
930+ FL rows cols
950 (a -> b) ->
932 (a -> b) ->
951 Relation cols rows
933 Relation cols rows
952−fromFRel' f =
934+fromFRel' = fromF'
953− let minA = minBound @a
957− ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
958− rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
959− elementsA = take ccols [minA .. maxA]
960− elementsB = take rrows [minB .. maxB]
961− combinations = (,) <$> elementsA <*> elementsB
962− combAp = map snd . sort . map (\(a, b) -> if f a == b
963− then ((fromEnum a, fromEnum b), nat 1)
964− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
965− mList = buildList combAp rrows
966− in tr $ fromLists mList
969− buildList l r = take r l : buildList (drop r l) r
971-- | Lifts functions to relations with dimensions matching @a@ and @b@
936-- | Lifts functions to relations with dimensions matching @a@ and @b@
972-- cardinality's.
937-- cardinality's.
973fromFRel ::
938fromFRel ::
974 forall a b.
939 forall a b.
975 ( Liftable Boolean a b,
940 ( Liftable Boolean a b,
976− CountableDimensionsN a b,
941+ CountableDimsN a b,
977− FromLists Boolean (Normalize b) (Normalize a)
942+ FLN b a
979 (a -> b) ->
944 (a -> b) ->
980 Relation (Normalize a) (Normalize b)
945 Relation (Normalize a) (Normalize b)
981−fromFRel f =
946+fromFRel = fromFRel'
982− let minA = minBound @a
986− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
987− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
988− elementsA = take ccols [minA .. maxA]
989− elementsB = take rrows [minB .. maxB]
990− combinations = (,) <$> elementsA <*> elementsB
991− combAp = map snd . sort . map (\(a, b) -> if f a == b
992− then ((fromEnum a, fromEnum b), nat 1)
993− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
994− mList = buildList combAp rrows
995− in tr $ fromLists mList
998− buildList l r = take r l : buildList (drop r l) r
1000-- | Lifts a relation function to a Boolean Matrix
948-- | Lifts a relation function to a Boolean Matrix
@@ -1005,17 +953,17 @@ toRel ::
1008− CountableDimensionsN a b,
956+ CountableDims a b,
1009− FromListsN Boolean b a
957+ FLN b a
1011 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
959 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
1012toRel f =
960toRel f =
1013 let minA = minBound @a
961 let minA = minBound @a
1014 maxA = maxBound @a
962 maxA = maxBound @a
1015 minB = minBound @b
963 minB = minBound @b
1016 maxB = maxBound @b
964 maxB = maxBound @b
1017− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
965+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
1018− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
966+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
1019 elementsA = take ccols [minA .. maxA]
967 elementsA = take ccols [minA .. maxA]
1020 elementsB = take rrows [minB .. maxB]
968 elementsB = take rrows [minB .. maxB]
1021 combinations = (,) <$> elementsA <*> elementsB
969 combinations = (,) <$> elementsA <*> elementsB