@@ -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,23 +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 -- * Constraint type aliases
53 Countable,
53 Countable,
54− CountableDims,
54+ CountableDimensions,
55 CountableN,
55 CountableN,
56− CountableDimsN,
56+ CountableDimensionsN,
62 -- * Primitives
61 -- * Primitives
@@ -86,9 +86,7 @@ module LAoP.Matrix.Internal
87 -- ** Get dimensions
87 -- ** Get dimensions
93 -- ** Matrix Transposition
91 -- ** Matrix Transposition
@@ -176,7 +174,6 @@ import Data.Kind
176import Data.List
174import Data.List
177import Data.Maybe
175import Data.Maybe
178import Data.Proxy
176import Data.Proxy
180import Data.Void
177import Data.Void
181import GHC.TypeLits
178import GHC.TypeLits
182import Data.Type.Equality
179import Data.Type.Equality
@@ -187,6 +184,7 @@ import qualified Prelude (id, (.))
188-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
185-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
189data Matrix e cols rows where
186data Matrix e cols rows where
187+ Empty :: Matrix e Void Void
190 One :: e -> Matrix e () ()
188 One :: e -> Matrix e () ()
191 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
189 Join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
192 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
190 Fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
@@ -216,6 +214,7 @@ type family Count (d :: Type) :: Nat where
217-- Thanks to Li-Yao Xia this type family is super fast.
215-- Thanks to Li-Yao Xia this type family is super fast.
218type family FromNat (n :: Nat) :: Type where
216type family FromNat (n :: Nat) :: Type where
219 FromNat 1 = ()
218 FromNat 1 = ()
220 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
219 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
@@ -232,26 +231,27 @@ type family Normalize (d :: Type) :: Type where
232-- | Constraint type synonyms to keep the type signatures less convoluted
231-- | Constraint type synonyms to keep the type signatures less convoluted
233type Countable a = KnownNat (Count a)
232type Countable a = KnownNat (Count a)
234type CountableN a = KnownNat (Count (Normalize a))
233type CountableN a = KnownNat (Count (Normalize a))
235−type CountableDims a b = (Countable a, Countable b)
234+type CountableDimensions a b = (Countable a, Countable b)
236−type CountableDimsN a b = (CountableN a, CountableN b)
235+type CountableDimensionsN a b = (CountableN a, CountableN b)
237−type FL a b = FromLists a b
238−type FLN a b = FromLists (Normalize a) (Normalize b)
236+type FromListsN e a b = FromLists e (Normalize a) (Normalize b)
239type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
237type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
240type Trivial a = FromNat (Count a) ~ a
238type Trivial a = FromNat (Count a) ~ a
242-- | It is possible to implement a constrained version of the category type
240-- | It is possible to implement a constrained version of the category type
244instance (Num e) => Category (Matrix e) where
242instance (Num e) => Category (Matrix e) where
245− type Object (Matrix e) a = (FL a a, Countable a)
243+ type Object (Matrix e) a = (FromLists e a a, Countable a)
246− id = iden
244+ id = iden
247 (.) = comp
245 (.) = comp
249instance NFData e => NFData (Matrix e cols rows) where
247instance NFData e => NFData (Matrix e cols rows) where
250 rnf (One e) = rnf e
249 rnf (One e) = rnf e
251 rnf (Join a b) = rnf a `seq` rnf b
250 rnf (Join a b) = rnf a `seq` rnf b
252 rnf (Fork a b) = rnf a `seq` rnf b
251 rnf (Fork a b) = rnf a `seq` rnf b
254instance Eq e => Eq (Matrix e cols rows) where
253instance Eq e => Eq (Matrix e cols rows) where
254+ Empty == Empty = True
255 (One a) == (One b) = a == b
255 (One a) == (One b) = a == b
256 (Join a b) == (Join c d) = a == c && b == d
256 (Join a b) == (Join c d) = a == c && b == d
257 (Fork a b) == (Fork c d) = a == c && b == d
257 (Fork a b) == (Fork c d) = a == c && b == d
@@ -259,21 +259,25 @@ instance Eq e => Eq (Matrix e cols rows) where
259 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
259 x@(Join _ _) == y@(Fork _ _) = abideJF x == y
261instance Num e => Num (Matrix e cols rows) where
261instance Num e => Num (Matrix e cols rows) where
262 a + b = zipWithM (+) a b
263 a + b = zipWithM (+) a b
264 a - b = zipWithM (-) a b
265 a - b = zipWithM (-) a b
266 a * b = zipWithM (*) a b
267 a * b = zipWithM (*) a b
268 abs (One a) = One (abs a)
270 abs (One a) = One (abs a)
269 abs (Join a b) = Join (abs a) (abs b)
271 abs (Join a b) = Join (abs a) (abs b)
270 abs (Fork a b) = Fork (abs a) (abs b)
272 abs (Fork a b) = Fork (abs a) (abs b)
274+ signum Empty = Empty
272 signum (One a) = One (signum a)
275 signum (One a) = One (signum a)
273 signum (Join a b) = Join (signum a) (signum b)
276 signum (Join a b) = Join (signum a) (signum b)
274 signum (Fork a b) = Fork (signum a) (signum b)
277 signum (Fork a b) = Fork (signum a) (signum b)
276instance Ord e => Ord (Matrix e cols rows) where
279instance Ord e => Ord (Matrix e cols rows) where
280+ Empty <= Empty = True
277 (One a) <= (One b) = a <= b
281 (One a) <= (One b) = a <= b
278 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
282 (Join a b) <= (Join c d) = (a <= c) && (b <= d)
279 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
283 (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
@@ -282,6 +286,10 @@ instance Ord e => Ord (Matrix e cols rows) where
283-- Primitives
287-- Primitives
289+-- | Empty matrix constructor
290+empty :: Matrix e Void Void
285-- | Unit matrix constructor
293-- | Unit matrix constructor
286one :: e -> Matrix e () ()
294one :: e -> Matrix e () ()
@@ -312,39 +320,40 @@ infixl 2 ===
313-- Given that it is not possible to branch on types at the term level type
321-- Given that it is not possible to branch on types at the term level type
314-- classes are needed very much like an inductive definition but on types.
322-- classes are needed very much like an inductive definition but on types.
315−class FromLists cols rows where
323+class FromLists e cols rows where
316 -- | Build a matrix out of a list of list of elements. Throws a runtime
324 -- | Build a matrix out of a list of list of elements. Throws a runtime
317 -- error if the dimensions do not match.
325 -- error if the dimensions do not match.
318 fromLists :: [[e]] -> Matrix e cols rows
326 fromLists :: [[e]] -> Matrix e cols rows
320−instance FromLists () () where
328+instance FromLists e Void Void where
329+ fromLists [] = Empty
330+ fromLists _ = error "Wrong dimensions"
332+instance {-# OVERLAPPING #-} FromLists e () () where
321 fromLists [[e]] = One e
333 fromLists [[e]] = One e
322 fromLists _ = error "Wrong dimensions"
334 fromLists _ = error "Wrong dimensions"
324−instance (FromLists cols ()) => FromLists (Either () cols) () where
336+instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
325 fromLists [h : t] = Join (One h) (fromLists [t])
337 fromLists [h : t] = Join (One h) (fromLists [t])
326 fromLists _ = error "Wrong dimensions"
338 fromLists _ = error "Wrong dimensions"
328−instance {-# OVERLAPPABLE #-}
329− (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
340+instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), Countable a) => FromLists e (Either a b) () where
330 fromLists [l] =
341 fromLists [l] =
331 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
342 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
332 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
343 in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
333 fromLists _ = error "Wrong dimensions"
344 fromLists _ = error "Wrong dimensions"
335−instance (FromLists () rows) => FromLists () (Either () rows) where
346+instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
336 fromLists ([h] : t) = Fork (One h) (fromLists t)
347 fromLists ([h] : t) = Fork (One h) (fromLists t)
337 fromLists _ = error "Wrong dimensions"
348 fromLists _ = error "Wrong dimensions"
339−instance {-# OVERLAPPABLE #-}
340− (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
350+instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) where
341− fromLists l@([_] : _) =
351+ fromLists l@([_] : _) =
342 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
352 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
343 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
353 in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
344 fromLists _ = error "Wrong dimensions"
354 fromLists _ = error "Wrong dimensions"
346−instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
356+instance {-# OVERLAPPABLE #-} (FromLists e (Either a b) c, FromLists e (Either a b) d, Countable c) => FromLists e (Either a b) (Either c d) where
347− => FromLists (Either a b) (Either c d) where
348 fromLists l@(h : t) =
357 fromLists l@(h : t) =
349 let lh = length h
358 let lh = length h
350 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
359 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
@@ -357,8 +366,8 @@ instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
357-- a construction function that operates with indices.
366-- a construction function that operates with indices.
358matrixBuilder' ::
367matrixBuilder' ::
359 forall e cols rows.
368 forall e cols rows.
360− ( FL cols rows,
369+ ( FromLists e cols rows,
361− CountableDims cols rows
370+ CountableDimensions cols rows
362 ) => ((Int, Int) -> e) -> Matrix e cols rows
371 ) => ((Int, Int) -> e) -> Matrix e cols rows
363matrixBuilder' f =
372matrixBuilder' f =
364 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
373 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
@@ -370,16 +379,17 @@ matrixBuilder' f =
370-- a construction function that operates with arbitrary types.
379-- a construction function that operates with arbitrary types.
371matrixBuilder ::
380matrixBuilder ::
372 forall e a b.
381 forall e a b.
373− ( FLN a b,
382+ ( FromListsN e a b,
376 Bounded a,
386 Bounded a,
377 Bounded b,
387 Bounded b,
379− Countable b
389+ CountableDimensionsN a b
380 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
390 ) => ((a, b) -> e) -> Matrix e (Normalize a) (Normalize b)
381matrixBuilder f =
391matrixBuilder f =
382− let r = fromInteger $ natVal (Proxy :: Proxy (Count b))
392+ let r = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
383 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
393 positions = [(a, b) | a <- [minBound .. maxBound], b <- [minBound .. maxBound]]
384 in fromLists . map (map f) . transpose . buildList r $ positions
394 in fromLists . map (map f) . transpose . buildList r $ positions
@@ -387,11 +397,11 @@ matrixBuilder f =
387 buildList r l = take r l : buildList r (drop r l)
397 buildList r l = take r l : buildList r (drop r l)
389-- | Constructs a column vector matrix
399-- | Constructs a column vector matrix
390−col :: (FL () rows) => [e] -> Matrix e () rows
400+col :: (FromLists e () rows) => [e] -> Matrix e () rows
391col = fromLists . map (: [])
401col = fromLists . map (: [])
393-- | Constructs a row vector matrix
403-- | Constructs a row vector matrix
394−row :: (FL cols ()) => [e] -> Matrix e cols ()
404+row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
395row = fromLists . (: [])
405row = fromLists . (: [])
397-- | Lifts functions to matrices with arbitrary dimensions.
407-- | Lifts functions to matrices with arbitrary dimensions.
@@ -401,8 +411,8 @@ row = fromLists . (: [])
402 forall a b cols rows e.
412 forall a b cols rows e.
403 ( Liftable e a b,
413 ( Liftable e a b,
404− CountableDims cols rows,
414+ CountableDimensions cols rows,
405− FL rows cols
415+ FromLists e rows cols
407 (a -> b) ->
417 (a -> b) ->
408 Matrix e cols rows
418 Matrix e cols rows
@@ -430,17 +440,35 @@ fromF' f =
431 forall a b e.
441 forall a b e.
432 ( Liftable e a b,
442 ( Liftable e a b,
433− CountableDimsN a b,
443+ CountableDimensionsN a b,
434− FLN b a
444+ FromListsN e b a
436 (a -> b) ->
446 (a -> b) ->
437 Matrix e (Normalize a) (Normalize b)
447 Matrix e (Normalize a) (Normalize b)
438−fromF = fromF'
448+fromF f =
449+ let minA = minBound @a
453+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
454+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
455+ elementsA = take ccols [minA .. maxA]
456+ elementsB = take rrows [minB .. maxB]
457+ combinations = (,) <$> elementsA <*> elementsB
458+ combAp = map snd . sort . map (\(a, b) -> if f a == b
459+ then ((fromEnum a, fromEnum b), 1)
460+ else ((fromEnum a, fromEnum b), 0)) $ combinations
461+ mList = buildList combAp rrows
462+ in tr $ fromLists mList
465+ buildList l r = take r l : buildList (drop r l) r
440-- Conversion
467-- Conversion
442-- | Converts a matrix to a list of lists of elements.
469-- | Converts a matrix to a list of lists of elements.
443toLists :: Matrix e cols rows -> [[e]]
470toLists :: Matrix e cols rows -> [[e]]
444toLists (One e) = [[e]]
472toLists (One e) = [[e]]
445toLists (Fork l r) = toLists l ++ toLists r
473toLists (Fork l r) = toLists l ++ toLists r
446toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
474toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
@@ -452,7 +480,7 @@ toList = concat . toLists
452-- Zeros Matrix
480-- Zeros Matrix
454-- | The zero matrix. A matrix wholly filled with zeros.
482-- | The zero matrix. A matrix wholly filled with zeros.
455−zeros :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
483+zeros :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
456zeros = matrixBuilder' (const 0)
484zeros = matrixBuilder' (const 0)
458-- Ones Matrix
486-- Ones Matrix
@@ -460,20 +488,20 @@ zeros = matrixBuilder' (const 0)
460-- | The ones matrix. A matrix wholly filled with ones.
488-- | The ones matrix. A matrix wholly filled with ones.
462-- Also known as T (Top) matrix.
490-- Also known as T (Top) matrix.
463−ones :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
491+ones :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
464ones = matrixBuilder' (const 1)
492ones = matrixBuilder' (const 1)
466-- Const Matrix
494-- Const Matrix
468-- | The constant matrix constructor. A matrix wholly filled with a given
496-- | The constant matrix constructor. A matrix wholly filled with a given
470−constant :: (Num e, FL cols rows, CountableDims cols rows) => e -> Matrix e cols rows
498+constant :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => e -> Matrix e cols rows
471constant e = matrixBuilder' (const e)
499constant e = matrixBuilder' (const e)
473-- Bang Matrix
501-- Bang Matrix
475-- | The T (Top) row vector matrix.
503-- | The T (Top) row vector matrix.
476−bang :: forall e cols. (Num e, Enum e, FL cols (), Countable cols) => Matrix e cols ()
504+bang :: forall e cols. (Num e, Enum e, FromLists e cols (), Countable cols) => Matrix e cols ()
478 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
506 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
479 in fromLists [take c [1, 1 ..]]
507 in fromLists [take c [1, 1 ..]]
@@ -481,7 +509,7 @@ bang =
481-- iden Matrix
509-- iden Matrix
483-- | iden matrix.
511-- | iden matrix.
484−iden :: forall e cols . (Num e, FL cols cols, Countable cols) => Matrix e cols cols
512+iden :: forall e cols . (Num e, FromLists e cols cols, Countable cols) => Matrix e cols cols
485iden = matrixBuilder' (bool 0 1 . uncurry (==))
513iden = matrixBuilder' (bool 0 1 . uncurry (==))
486{-# NOINLINE iden #-}
514{-# NOINLINE iden #-}
@@ -492,12 +520,13 @@ iden = matrixBuilder' (bool 0 1 . uncurry (==))
492-- This definition takes advantage of divide-and-conquer and fusion laws
520-- This definition takes advantage of divide-and-conquer and fusion laws
493-- from LAoP.
521-- from LAoP.
494comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
522comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
523+comp Empty Empty = Empty
495comp (One a) (One b) = One (a * b)
524comp (One a) (One b) = One (a * b)
496comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
525comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
497comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
526comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
498comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
527comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
499{-# NOINLINE comp #-}
528{-# NOINLINE comp #-}
500−{-# RULES
529+{-# RULES
501 "comp/iden1" forall m. comp m iden = m ;
530 "comp/iden1" forall m. comp m iden = m ;
502 "comp/iden2" forall m. comp iden m = m
531 "comp/iden2" forall m. comp iden m = m
@@ -507,6 +536,7 @@ comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
507infixl 7 .|
536infixl 7 .|
508-- | Scalar multiplication of matrices.
537-- | Scalar multiplication of matrices.
509(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
538(.|) :: Num e => e -> Matrix e cols rows -> Matrix e cols rows
510(.|) e (One a) = One (e * a)
540(.|) e (One a) = One (e * a)
511(.|) e (Join a b) = Join (e .| a) (e .| b)
541(.|) e (Join a b) = Join (e .| a) (e .| b)
512(.|) e (Fork a b) = Fork (e .| a) (e .| b)
542(.|) e (Fork a b) = Fork (e .| a) (e .| b)
@@ -516,6 +546,7 @@ infixl 7 .|
516infixl 7 ./
546infixl 7 ./
517-- | Scalar multiplication of matrices.
547-- | Scalar multiplication of matrices.
518(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
548(./) :: Fractional e => Matrix e cols rows -> e -> Matrix e cols rows
519(./) (One a) e = One (a / e)
550(./) (One a) e = One (a / e)
520(./) (Join a b) e = Join (a ./ e) (b ./ e)
551(./) (Join a b) e = Join (a ./ e) (b ./ e)
521(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
552(./) (Fork a b) e = Fork (a ./ e) (b ./ e)
@@ -523,59 +554,45 @@ infixl 7 ./
523-- Projections
554-- Projections
525-- | Biproduct first component projection
556-- | Biproduct first component projection
526−p1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e (Either m n) m
557+p1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e (Either m n) m
527p1 = join id zeros
558p1 = join id zeros
529-- | Biproduct second component projection
560-- | Biproduct second component projection
530−p2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e (Either m n) n
561+p2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e (Either m n) n
531p2 = join zeros id
562p2 = join zeros id
533-- Injections
564-- Injections
535-- | Biproduct first component injection
566-- | Biproduct first component injection
536−i1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e m (Either m n)
567+i1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e m (Either m n)
537i1 = tr p1
568i1 = tr p1
539-- | Biproduct second component injection
570-- | Biproduct second component injection
540−i2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e n (Either m n)
571+i2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e n (Either m n)
541i2 = tr p2
572i2 = tr p2
543-- Dimensions
574-- Dimensions
545-- | Obtain the number of rows.
576-- | Obtain the number of rows.
547−-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
578+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
548−-- dimensions in constant time. For a version that doesn't require the
579+-- dimensions in constant time.
549−-- constraint see 'rows''.
580+--
581+-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
582+-- exchange for performance.
550rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
583rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
551rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
584rows _ = 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
562-- | Obtain the number of columns.
586-- | Obtain the number of columns.
588+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
589+-- dimensions in constant time.
564−-- NOTE: The 'KnownNat' constraint is needed in order to obtain the
591+-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
565−-- dimensions in constant time. For a version that doesn't require the
592+-- exchange for performance.
566−-- constraint see 'columns''.
567columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
593columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
568columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
594columns _ = 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
579-- Coproduct Bifunctor
596-- Coproduct Bifunctor
581infixl 5 -|-
598infixl 5 -|-
@@ -584,11 +601,11 @@ infixl 5 -|-
585 forall e n k m j.
602 forall e n k m j.
587− CountableDims j k,
604+ CountableDimensions j k,
588− FL k k,
605+ FromLists e k k,
589− FL j k,
606+ FromLists e j k,
590− FL k j,
607+ FromLists e k j,
591− FL j j
608+ FromLists e j j
593 Matrix e n k ->
610 Matrix e n k ->
594 Matrix e m j ->
611 Matrix e m j ->
@@ -601,8 +618,8 @@ infixl 5 -|-
602 forall e m k .
619 forall e m k .
604− CountableDims k m,
621+ CountableDimensions k m,
605− FL (Normalize (m, k)) m,
622+ FromLists e (Normalize (m, k)) m,
606 CountableN (m, k)
623 CountableN (m, k)
607 ) => Matrix e (Normalize (m, k)) m
624 ) => Matrix e (Normalize (m, k)) m
608fstM = matrixBuilder' f
625fstM = matrixBuilder' f
@@ -616,8 +633,8 @@ fstM = matrixBuilder' f
617 forall e m k .
634 forall e m k .
619− CountableDims k m,
636+ CountableDimensions k m,
620− FL (Normalize (m, k)) k,
637+ FromLists e (Normalize (m, k)) k,
621 CountableN (m, k)
638 CountableN (m, k)
622 ) => Matrix e (Normalize (m, k)) k
639 ) => Matrix e (Normalize (m, k)) k
623sndM = matrixBuilder' f
640sndM = matrixBuilder' f
@@ -630,7 +647,7 @@ sndM = matrixBuilder' f
630-- | Khatri Rao Matrix product also known as matrix pairing.
647-- | Khatri Rao Matrix product also known as matrix pairing.
632-- NOTE: That this is not a true categorical product, see for instance:
649-- NOTE: That this is not a true categorical product, see for instance:
635-- | fstM . kr a b == a
652-- | fstM . kr a b == a
636-- kr a b ==> |
653-- kr a b ==> |
@@ -641,10 +658,10 @@ sndM = matrixBuilder' f
642 forall e cols a b.
659 forall e cols a b.
644− CountableDims a b,
661+ CountableDimensions a b,
645 CountableN (a, b),
662 CountableN (a, b),
646− FL (Normalize (a, b)) a,
663+ FromLists e (Normalize (a, b)) a,
647− FL (Normalize (a, b)) b
664+ FromLists e (Normalize (a, b)) b
648 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
665 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
650 let fstM' = fstM @e @a @b
667 let fstM' = fstM @e @a @b
@@ -659,14 +676,14 @@ infixl 4 ><
660 forall e m p n q.
677 forall e m p n q.
662− CountableDims m n,
679+ CountableDimensions m n,
663− CountableDims p q,
680+ CountableDimensions p q,
664− CountableDimsN (m, n) (p, q),
681+ CountableDimensionsN (m, n) (p, q),
665− FL (Normalize (m, n)) m,
682+ FromLists e (Normalize (m, n)) m,
666− FL (Normalize (m, n)) n,
683+ FromLists e (Normalize (m, n)) n,
667− FL (Normalize (p, q)) p,
684+ FromLists e (Normalize (p, q)) p,
668− FL (Normalize (p, q)) q
685+ FromLists e (Normalize (p, q)) q
670 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
687 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
671(><) a b =
688(><) a b =
672 let fstM' = fstM @e @m @n
689 let fstM' = fstM @e @m @n
@@ -684,6 +701,7 @@ infixl 4 ><
685abideJF :: Matrix e cols rows -> Matrix e cols rows
702abideJF :: Matrix e cols rows -> Matrix e cols rows
686abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
703abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
704+abideJF Empty = Empty
687abideJF (One e) = One e
705abideJF (One e) = One e
688abideJF (Join a b) = Join (abideJF a) (abideJF b)
706abideJF (Join a b) = Join (abideJF a) (abideJF b)
689abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
707abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
@@ -697,6 +715,7 @@ abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
698abideFJ :: Matrix e cols rows -> Matrix e cols rows
716abideFJ :: Matrix e cols rows -> Matrix e cols rows
699abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
717abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
718+abideFJ Empty = Empty
700abideFJ (One e) = One e
719abideFJ (One e) = One e
701abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
720abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
702abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
721abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
@@ -705,6 +724,7 @@ abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
706-- | Matrix transposition.
725-- | Matrix transposition.
707tr :: Matrix e cols rows -> Matrix e rows cols
726tr :: Matrix e cols rows -> Matrix e rows cols
708tr (One e) = One e
728tr (One e) = One e
709tr (Join a b) = Fork (tr a) (tr b)
729tr (Join a b) = Fork (tr a) (tr b)
710tr (Fork a b) = Join (tr a) (tr b)
730tr (Fork a b) = Join (tr a) (tr b)
@@ -713,32 +733,32 @@ tr (Fork a b) = Join (tr a) (tr b)
714-- | Selective functors 'select' operator equivalent inspired by the
734-- | Selective functors 'select' operator equivalent inspired by the
715-- ArrowMonad solution presented in the paper.
735-- 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
736+select :: (Num e, FromLists e b b, Countable b) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
717select (Fork a b) y = y . a + b -- Divide-and-conquer law
737select (Fork a b) y = y . a + b -- Divide-and-conquer law
718select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
738select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
719select m y = join y id . m
739select m y = join y id . m
723− CountableDims a b,
743+ CountableDimensions a b,
724− CountableDims c (Either b c),
744+ CountableDimensions c (Either b c),
725− FL c b,
745+ FromLists e c b,
726− FL a b,
746+ FromLists e a b,
727− FL a a,
747+ FromLists e a a,
728− FL b b,
748+ FromLists e b b,
729− FL c c,
749+ FromLists e c c,
730− FL b a,
750+ FromLists e b a,
731− FL b c,
751+ FromLists e b c,
732− FL (Either b c) b,
752+ FromLists e (Either b c) b,
733− FL (Either b c) c
753+ FromLists e (Either b c) c
735 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
755 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
736branch x l r = f x `select` g l `select` r
756branch x l r = f x `select` g l `select` r
738− f :: (Num e, Countable a, CountableDims b c, FL a b, FL c b, FL b b, FL b a, FL a a)
758+ f :: (Num e, Countable a, CountableDimensions b c, FromLists e a b, FromLists e c b, FromLists e b b, FromLists e b a, FromLists e a a)
739 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
759 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
740 f m = fork (tr i1) (i1 . tr i2) . m
760 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)
761+ g :: (Num e, CountableDimensions b c, FromLists e b c, FromLists e c c) => Matrix e a c -> Matrix e a (Either b c)
742 g m = i2 . m
762 g m = i2 . m
744-- McCarthy's Conditional
764-- McCarthy's Conditional
@@ -747,9 +767,9 @@ branch x l r = f x `select` g l `select` r
748 ( Trivial cols,
768 ( Trivial cols,
749 Countable cols,
769 Countable cols,
750− FL () cols,
770+ FromLists e () cols,
751− FL cols (),
771+ FromLists e cols (),
752− FL cols cols,
772+ FromLists e cols cols,
753 Bounded a,
773 Bounded a,
@@ -762,9 +782,9 @@ cond p f g = join f g . grd p
763 ( Trivial q,
783 ( Trivial q,
764 Countable q,
784 Countable q,
765− FL () q,
785+ FromLists e () q,
766− FL q (),
786+ FromLists e q (),
767− FL q q,
787+ FromLists e q q,
768 Bounded a,
788 Bounded a,
@@ -778,9 +798,9 @@ corr ::
778 forall e a q .
798 forall e a q .
779 ( Trivial q,
799 ( Trivial q,
780 Countable q,
800 Countable q,
781− FL () q,
801+ FromLists e () q,
782− FL q (),
802+ FromLists e q (),
783− FL q q,
803+ FromLists e q q,
784 Liftable e a Bool
804 Liftable e a Bool
786 => (a -> Bool) -> Matrix e q q
806 => (a -> Bool) -> Matrix e q q
@@ -809,7 +829,7 @@ prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
809 fill str = replicate (widest - length str - 2) ' ' ++ str
829 fill str = replicate (widest - length str - 2) ' ' ++ str
811-- | Matrix pretty printer
831-- | Matrix pretty printer
812−pretty :: (CountableDims cols rows, Show e) => Matrix e cols rows -> String
832+pretty :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> String
813pretty m = concat
833pretty m = concat
814 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
834 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
815 , unlines
835 , unlines
@@ -838,11 +858,12 @@ pretty m = concat
838 (safeGet i j m)
858 (safeGet i j m)
840-- | Matrix pretty printer
860-- | Matrix pretty printer
841−prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
861+prettyPrint :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> IO ()
842prettyPrint = putStrLn . pretty
862prettyPrint = putStrLn . pretty
844-- | Zip two matrices with a given binary function
864-- | Zip two matrices with a given binary function
845zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
865zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
866+zipWithM _ Empty Empty = Empty
846zipWithM f (One a) (One b) = One (f a b)
867zipWithM f (One a) (One b) = One (f a b)
847zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
868zipWithM f (Join a b) (Join c d) = Join (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)
869zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
@@ -867,12 +888,14 @@ fromBool False = nat 0
868-- | Relational negation
889-- | Relational negation
869negateM :: Relation cols rows -> Relation cols rows
890negateM :: Relation cols rows -> Relation cols rows
891+negateM Empty = Empty
870negateM (One (Nat p)) = One (Nat (negate p))
892negateM (One (Nat p)) = One (Nat (negate p))
871negateM (Join a b) = Join (negateM a) (negateM b)
893negateM (Join a b) = Join (negateM a) (negateM b)
872negateM (Fork a b) = Fork (negateM a) (negateM b)
894negateM (Fork a b) = Fork (negateM a) (negateM b)
874-- | Relational addition
896-- | Relational addition
875orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
897orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
898+orM Empty Empty = Empty
876orM (One a) (One b) = One (fromBool (toBool a || toBool b))
899orM (One a) (One b) = One (fromBool (toBool a || toBool b))
877orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
900orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
878orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
901orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
@@ -881,6 +904,7 @@ orM x@(Join _ _) y@(Fork _ _) = orM (abideJF x) y
882-- | Relational multiplication
905-- | Relational multiplication
883andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
906andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
907+andM Empty Empty = Empty
884andM (One a) (One b) = One (fromBool (toBool a && toBool b))
908andM (One a) (One b) = One (fromBool (toBool a && toBool b))
885andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
909andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
886andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
910andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
@@ -889,6 +913,7 @@ andM x@(Join _ _) y@(Fork _ _) = andM (abideJF x) y
890-- | Relational subtraction
914-- | Relational subtraction
891subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
915subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
916+subM Empty Empty = Empty
892subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
917subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
893subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
918subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
894subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
919subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
@@ -897,6 +922,7 @@ subM x@(Join _ _) y@(Fork _ _) = subM (abideJF x) y
898-- | Matrix relational composition.
923-- | Matrix relational composition.
899compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
924compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
925+compRel Empty Empty = Empty
900compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
926compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
901compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
927compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
902compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
928compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
@@ -904,6 +930,7 @@ compRel c (Join a b) = Join (compRel c a) (compRel c b) -- Join fusion
905-- | Matrix relational right division
931-- | Matrix relational right division
906divR :: Relation b c -> Relation b a -> Relation a c
932divR :: Relation b c -> Relation b a -> Relation a c
933+divR Empty Empty = Empty
907divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
934divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
908divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
935divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
909divR (Fork a b) c = Fork (divR a c) (divR b c)
936divR (Fork a b) c = Fork (divR a c) (divR b c)
@@ -926,24 +953,58 @@ divS s r = divL r s `intersection` divR (tr r) (tr s)
926fromFRel' ::
953fromFRel' ::
927 forall a b cols rows.
954 forall a b cols rows.
928 ( Liftable Boolean a b,
955 ( Liftable Boolean a b,
929− CountableDims cols rows,
956+ CountableDimensions cols rows,
930− FL rows cols
957+ FromLists Boolean rows cols
932 (a -> b) ->
959 (a -> b) ->
933 Relation cols rows
960 Relation cols rows
934−fromFRel' = fromF'
961+fromFRel' f =
962+ let minA = minBound @a
966+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
967+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
968+ elementsA = take ccols [minA .. maxA]
969+ elementsB = take rrows [minB .. maxB]
970+ combinations = (,) <$> elementsA <*> elementsB
971+ combAp = map snd . sort . map (\(a, b) -> if f a == b
972+ then ((fromEnum a, fromEnum b), nat 1)
973+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
974+ mList = buildList combAp rrows
975+ in tr $ fromLists mList
978+ buildList l r = take r l : buildList (drop r l) r
936-- | Lifts functions to relations with dimensions matching @a@ and @b@
980-- | Lifts functions to relations with dimensions matching @a@ and @b@
937-- cardinality's.
981-- cardinality's.
938fromFRel ::
982fromFRel ::
939 forall a b.
983 forall a b.
940 ( Liftable Boolean a b,
984 ( Liftable Boolean a b,
941− CountableDimsN a b,
985+ CountableDimensionsN a b,
942− FLN b a
986+ FromLists Boolean (Normalize b) (Normalize a)
944 (a -> b) ->
988 (a -> b) ->
945 Relation (Normalize a) (Normalize b)
989 Relation (Normalize a) (Normalize b)
946−fromFRel = fromFRel'
990+fromFRel f =
991+ let minA = minBound @a
995+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
996+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
997+ elementsA = take ccols [minA .. maxA]
998+ elementsB = take rrows [minB .. maxB]
999+ combinations = (,) <$> elementsA <*> elementsB
1000+ combAp = map snd . sort . map (\(a, b) -> if f a == b
1001+ then ((fromEnum a, fromEnum b), nat 1)
1002+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
1003+ mList = buildList combAp rrows
1004+ in tr $ fromLists mList
1006+ buildList [] _ = []
1007+ buildList l r = take r l : buildList (drop r l) r
948-- | Lifts a relation function to a Boolean Matrix
1009-- | Lifts a relation function to a Boolean Matrix
@@ -953,17 +1014,17 @@ toRel ::
956− CountableDims a b,
1017+ CountableDimensionsN a b,
957− FLN b a
1018+ FromListsN Boolean b a
959 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
1020 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
960toRel f =
1021toRel f =
961 let minA = minBound @a
1022 let minA = minBound @a
962 maxA = maxBound @a
1023 maxA = maxBound @a
963 minB = minBound @b
1024 minB = minBound @b
964 maxB = maxBound @b
1025 maxB = maxBound @b
965− ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
1026+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
966− rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
1027+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
967 elementsA = take ccols [minA .. maxA]
1028 elementsA = take ccols [minA .. maxA]
968 elementsB = take rrows [minB .. maxB]
1029 elementsB = take rrows [minB .. maxB]
969 combinations = (,) <$> elementsA <*> elementsB
1030 combinations = (,) <$> elementsA <*> elementsB