@@ -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,26 +43,17 @@ module LAoP.Matrix.Internal
4343 --
4444 -- There exists two type families that make it easier to write
4545 -- matrix dimensions: 'FromNat' and 'Count'. This approach
46− -- leads to a very straightforward implementation
47− -- of LAoP combinators.
46+ -- leads to a very straightforward implementation
47+ -- of LAoP combinators.
4848
4949 -- * Type safe matrix representation
5050 Matrix (..),
5151
52− -- * Constraint type aliases
53− Countable,
54− CountableDims,
55− CountableN,
56− CountableDimsN,
57− FL,
58− FLN,
59− Liftable,
60− Trivial,
61−
6252 -- * Primitives
53+ empty,
6354 one,
64− join,
65− fork,
55+ junc,
56+ split,
6657
6758 -- * Auxiliary type families
6859 FromNat,
@@ -75,7 +66,6 @@ module LAoP.Matrix.Internal
7566 toLists,
7667 toList,
7768 matrixBuilder,
78− matrixBuilder',
7969 row,
8070 col,
8171 zeros,
@@ -86,17 +76,11 @@ module LAoP.Matrix.Internal
8676 -- * Misc
8777 -- ** Get dimensions
8878 columns,
89− columns',
9079 rows,
91− rows',
9280
9381 -- ** Matrix Transposition
9482 tr,
9583
96− -- ** Scalar multiplication/division of matrices
97− (.|),
98− (./),
99−
10084 -- ** Selective operator
10185 select,
10286 branch,
@@ -105,19 +89,19 @@ module LAoP.Matrix.Internal
10589 cond,
10690
10791 -- ** Matrix "abiding"
108− abideJF,
109− abideFJ,
92+ abideJS,
93+ abideSJ,
11094
11195 -- ** Zip matrices
11296 zipWithM,
11397
11498 -- * Biproduct approach
115− -- ** Fork
99+ -- ** Split
116100 (===),
117101 -- *** Projections
118102 p1,
119103 p2,
120− -- ** Join
104+ -- ** Junc
121105 (|||),
122106 -- *** Injections
123107 i1,
@@ -130,13 +114,12 @@ module LAoP.Matrix.Internal
130114
131115 -- | Note that given the restrictions imposed it is not possible to
132116 -- implement the standard type classes present in standard Haskell.
133−
134117 -- *** Matrix pairing projections
135− fstM,
136− sndM,
118+ kp1,
119+ kp2,
137120
138121 -- *** Matrix pairing
139− kr,
122+ khatri,
140123
141124 -- * Matrix composition and lifting
142125
@@ -144,10 +127,10 @@ module LAoP.Matrix.Internal
144127
145128 -- | Note that given the restrictions imposed it is not possible to
146129 -- implement the standard type classes present in standard Haskell.
147− iden,
130+ identity,
148131 comp,
149− fromF',
150132 fromF,
133+ fromF',
151134
152135 -- * Matrix printing
153136 pretty,
@@ -176,20 +159,20 @@ import Data.Kind
176159import Data.List
177160import Data.Maybe
178161import Data.Proxy
179−import Data.Typeable
180162import Data.Void
181163import GHC.TypeLits
182164import Data.Type.Equality
183165import GHC.Generics
184166import Control.DeepSeq
185−import Prelude hiding (id, (.))
186−import qualified Prelude (id, (.))
167+import Control.Category
168+import Prelude hiding ((.))
187169
188170-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
189171data Matrix e cols rows where
172+ Empty :: Matrix e Void Void
190173 One :: e -> Matrix e () ()
191− 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)
174+ Junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
175+ Split :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
193176
194177deriving instance (Show e) => Show (Matrix e cols rows)
195178
@@ -216,6 +199,7 @@ type family Count (d :: Type) :: Nat where
216199--
217200-- Thanks to Li-Yao Xia this type family is super fast.
218201type family FromNat (n :: Nat) :: Type where
202+ FromNat 0 = Void
219203 FromNat 1 = ()
220204 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
221205
@@ -232,79 +216,90 @@ type family Normalize (d :: Type) :: Type where
232216-- | Constraint type synonyms to keep the type signatures less convoluted
233217type Countable a = KnownNat (Count a)
234218type CountableN a = KnownNat (Count (Normalize a))
235−type CountableDims a b = (Countable a, Countable b)
236−type CountableDimsN a b = (CountableN a, CountableN b)
237−type FL a b = FromLists a b
238−type FLN a b = FromLists (Normalize a) (Normalize b)
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)
239222type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
240223type Trivial a = FromNat (Count a) ~ a
241224
242−-- | It is possible to implement a constrained version of the category type
243−-- class.
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 'identity' instead.
244230instance (Num e) => Category (Matrix e) where
245− type Object (Matrix e) a = (FL a a, Countable a)
246− id = iden
247− (.) = comp
231+ id = undefined
232+ (.) = comp
248233
249234instance NFData e => NFData (Matrix e cols rows) where
250− rnf (One e) = rnf e
251− rnf (Join a b) = rnf a `seq` rnf b
252− rnf (Fork a b) = rnf a `seq` rnf b
235+ rnf Empty = ()
236+ rnf (One e) = rnf e
237+ rnf (Junc a b) = rnf a `seq` rnf b
238+ rnf (Split a b) = rnf a `seq` rnf b
253239
254240instance Eq e => Eq (Matrix e cols rows) where
255− (One a) == (One b) = a == b
256− (Join a b) == (Join c d) = a == c && b == d
257− (Fork a b) == (Fork c d) = a == c && b == d
258− x@(Fork _ _) == y@(Join _ _) = x == abideJF y
259− x@(Join _ _) == y@(Fork _ _) = abideJF x == y
241+ Empty == Empty = True
242+ (One a) == (One b) = a == b
243+ (Junc a b) == (Junc c d) = a == c && b == d
244+ (Split a b) == (Split c d) = a == c && b == d
245+ x@(Split _ _) == y@(Junc _ _) = x == abideJS y
246+ x@(Junc _ _) == y@(Split _ _) = abideJS x == y
260247
261248instance Num e => Num (Matrix e cols rows) where
249+
262250 a + b = zipWithM (+) a b
263251
264252 a - b = zipWithM (-) a b
265253
266254 a * b = zipWithM (*) a b
267255
268− abs (One a) = One (abs a)
269− abs (Join a b) = Join (abs a) (abs b)
270− abs (Fork a b) = Fork (abs a) (abs b)
256+ abs Empty = Empty
257+ abs (One a) = One (abs a)
258+ abs (Junc a b) = Junc (abs a) (abs b)
259+ abs (Split a b) = Split (abs a) (abs b)
271260
272− signum (One a) = One (signum a)
273− signum (Join a b) = Join (signum a) (signum b)
274− signum (Fork a b) = Fork (signum a) (signum b)
261+ signum Empty = Empty
262+ signum (One a) = One (signum a)
263+ signum (Junc a b) = Junc (signum a) (signum b)
264+ signum (Split a b) = Split (signum a) (signum b)
275265
276266instance Ord e => Ord (Matrix e cols rows) where
277− (One a) <= (One b) = a <= b
278− (Join a b) <= (Join c d) = (a <= c) && (b <= d)
279− (Fork a b) <= (Fork c d) = (a <= c) && (b <= d)
280− x@(Fork _ _) <= y@(Join _ _) = x <= abideJF y
281− x@(Join _ _) <= y@(Fork _ _) = abideJF x <= y
267+ Empty <= Empty = True
268+ (One a) <= (One b) = a <= b
269+ (Junc a b) <= (Junc c d) = (a <= c) && (b <= d)
270+ (Split a b) <= (Split c d) = (a <= c) && (b <= d)
271+ x@(Split _ _) <= y@(Junc _ _) = x <= abideJS y
272+ x@(Junc _ _) <= y@(Split _ _) = abideJS x <= y
282273
283274-- Primitives
284275
276+-- | Empty matrix constructor
277+empty :: Matrix e Void Void
278+empty = Empty
279+
285280-- | Unit matrix constructor
286281one :: e -> Matrix e () ()
287282one = One
288283
289−-- | Matrix 'Join' constructor
290−join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
291−join = Join
284+-- | Matrix 'Junc' constructor
285+junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
286+junc = Junc
292287
293288infixl 3 |||
294289
295−-- | Matrix 'Join' constructor
290+-- | Matrix 'Junc' constructor
296291(|||) :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
297−(|||) = Join
292+(|||) = Junc
298293
299−-- | Matrix 'Fork' constructor
300−fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
301−fork = Fork
294+-- | Matrix 'Split' constructor
295+split :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
296+split = Split
302297
303298infixl 2 ===
304299
305−-- | Matrix 'Fork' constructor
300+-- | Matrix 'Split' constructor
306301(===) :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
307−(===) = Fork
302+(===) = Split
308303
309304-- Construction
310305
@@ -312,101 +307,84 @@ infixl 2 ===
312307--
313308-- Given that it is not possible to branch on types at the term level type
314309-- classes are needed very much like an inductive definition but on types.
315−class FromLists cols rows where
310+class FromLists e cols rows where
316311 -- | Build a matrix out of a list of list of elements. Throws a runtime
317312 -- error if the dimensions do not match.
318313 fromLists :: [[e]] -> Matrix e cols rows
319314
320−instance FromLists () () where
315+instance FromLists e Void Void where
316+ fromLists [] = Empty
317+ fromLists _ = error "Wrong dimensions"
318+
319+instance {-# OVERLAPPING #-} FromLists e () () where
321320 fromLists [[e]] = One e
322321 fromLists _ = error "Wrong dimensions"
323322
324−instance (FromLists cols ()) => FromLists (Either () cols) () where
325− fromLists [h : t] = Join (One h) (fromLists [t])
323+instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
324+ fromLists [h : t] = Junc (One h) (fromLists [t])
326325 fromLists _ = error "Wrong dimensions"
327326
328−instance {-# OVERLAPPABLE #-}
329− (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
330− fromLists [l] =
327+instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), Countable a) => FromLists e (Either a b) () where
328+ fromLists [l] =
331329 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
332− in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
330+ in Junc (fromLists [take rowsA l]) (fromLists [drop rowsA l])
333331 fromLists _ = error "Wrong dimensions"
334332
335−instance (FromLists () rows) => FromLists () (Either () rows) where
336− fromLists ([h] : t) = Fork (One h) (fromLists t)
333+instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
334+ fromLists ([h] : t) = Split (One h) (fromLists t)
337335 fromLists _ = error "Wrong dimensions"
338336
339−instance {-# OVERLAPPABLE #-}
340− (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
341− fromLists l@([_] : _) =
337+instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, Countable a) => FromLists e () (Either a b) where
338+ fromLists l@([_] : _) =
342339 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
343− in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
340+ in Split (fromLists (take rowsA l)) (fromLists (drop rowsA l))
344341 fromLists _ = error "Wrong dimensions"
345342
346−instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
347− => FromLists (Either a b) (Either c d) where
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
348344 fromLists l@(h : t) =
349345 let lh = length h
350346 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
351− condition = all ((== lh) . length) t
347+ condition = all (== lh) (map length t)
352348 in if lh > 0 && condition
353− then Fork (fromLists (take rowsC l)) (fromLists (drop rowsC l))
349+ then Split (fromLists (take rowsC l)) (fromLists (drop rowsC l))
354350 else error "Not all rows have the same length"
355351
356352-- | Matrix builder function. Constructs a matrix provided with
357−-- a construction function that operates with indices.
358−matrixBuilder' ::
353+-- a construction function.
354+matrixBuilder ::
359355 forall e cols rows.
360− ( FL cols rows,
361− CountableDims cols rows
362− ) => ((Int, Int) -> e) -> Matrix e cols rows
363−matrixBuilder' f =
356+ ( FromLists e cols rows,
357+ CountableDimensions cols rows
358+ ) =>
359+ ((Int, Int) -> e) ->
360+ Matrix e cols rows
361+matrixBuilder f =
364362 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
365363 r = fromInteger $ natVal (Proxy :: Proxy (Count rows))
366364 positions = [(a, b) | a <- [0 .. (r - 1)], b <- [0 .. (c - 1)]]
367365 in fromLists . map (map f) . groupBy (\(x, _) (w, _) -> x == w) $ positions
368366
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−
389367-- | Constructs a column vector matrix
390−col :: (FL () rows) => [e] -> Matrix e () rows
368+col :: (FromLists e () rows) => [e] -> Matrix e () rows
391369col = fromLists . map (: [])
392370
393371-- | Constructs a row vector matrix
394−row :: (FL cols ()) => [e] -> Matrix e cols ()
372+row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
395373row = fromLists . (: [])
396374
397375-- | Lifts functions to matrices with arbitrary dimensions.
398376--
399377-- NOTE: Be careful to not ask for a matrix bigger than the cardinality of
400378-- types @a@ or @b@ allows.
401−fromF' ::
379+fromF ::
402380 forall a b cols rows e.
403381 ( Liftable e a b,
404− CountableDims cols rows,
405− FL rows cols
382+ CountableDimensions cols rows,
383+ FromLists e rows cols
406384 ) =>
407385 (a -> b) ->
408386 Matrix e cols rows
409−fromF' f =
387+fromF f =
410388 let minA = minBound @a
411389 maxA = maxBound @a
412390 minB = minBound @b
@@ -416,8 +394,8 @@ fromF' f =
416394 elementsA = take ccols [minA .. maxA]
417395 elementsB = take rrows [minB .. maxB]
418396 combinations = (,) <$> elementsA <*> elementsB
419− combAp = map snd . sort . map (\(a, b) -> if f a == b
420− then ((fromEnum a, fromEnum b), 1)
397+ combAp = map snd . sort . map (\(a, b) -> if f a == b
398+ then ((fromEnum a, fromEnum b), 1)
421399 else ((fromEnum a, fromEnum b), 0)) $ combinations
422400 mList = buildList combAp rrows
423401 in tr $ fromLists mList
@@ -427,23 +405,41 @@ fromF' f =
427405
428406-- | Lifts functions to matrices with dimensions matching @a@ and @b@
429407-- cardinality's.
430−fromF ::
408+fromF' ::
431409 forall a b e.
432410 ( Liftable e a b,
433− CountableDimsN a b,
434− FLN b a
411+ CountableDimensionsN a b,
412+ FromListsN e b a
435413 ) =>
436414 (a -> b) ->
437415 Matrix e (Normalize a) (Normalize b)
438−fromF = fromF'
416+fromF' f =
417+ let minA = minBound @a
418+ maxA = maxBound @a
419+ minB = minBound @b
420+ maxB = maxBound @b
421+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
422+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
423+ elementsA = take ccols [minA .. maxA]
424+ elementsB = take rrows [minB .. maxB]
425+ combinations = (,) <$> elementsA <*> elementsB
426+ combAp = map snd . sort . map (\(a, b) -> if f a == b
427+ then ((fromEnum a, fromEnum b), 1)
428+ else ((fromEnum a, fromEnum b), 0)) $ combinations
429+ mList = buildList combAp rrows
430+ in tr $ fromLists mList
431+ where
432+ buildList [] _ = []
433+ buildList l r = take r l : buildList (drop r l) r
439434
440435-- Conversion
441436
442437-- | Converts a matrix to a list of lists of elements.
443438toLists :: Matrix e cols rows -> [[e]]
439+toLists Empty = []
444440toLists (One e) = [[e]]
445−toLists (Fork l r) = toLists l ++ toLists r
446−toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
441+toLists (Split l r) = toLists l ++ toLists r
442+toLists (Junc l r) = zipWith (++) (toLists l) (toLists r)
447443
448444-- | Converts a matrix to a list of elements.
449445toList :: Matrix e cols rows -> [e]
@@ -452,38 +448,38 @@ toList = concat . toLists
452448-- Zeros Matrix
453449
454450-- | The zero matrix. A matrix wholly filled with zeros.
455−zeros :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
456−zeros = matrixBuilder' (const 0)
451+zeros :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
452+zeros = matrixBuilder (const 0)
457453
458454-- Ones Matrix
459455
460456-- | The ones matrix. A matrix wholly filled with ones.
461457--
462458-- Also known as T (Top) matrix.
463−ones :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
464−ones = matrixBuilder' (const 1)
459+ones :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => Matrix e cols rows
460+ones = matrixBuilder (const 1)
465461
466462-- Const Matrix
467463
468464-- | The constant matrix constructor. A matrix wholly filled with a given
469465-- value.
470−constant :: (Num e, FL cols rows, CountableDims cols rows) => e -> Matrix e cols rows
471−constant e = matrixBuilder' (const e)
466+constant :: (Num e, FromLists e cols rows, CountableDimensions cols rows) => e -> Matrix e cols rows
467+constant e = matrixBuilder (const e)
472468
473469-- Bang Matrix
474470
475471-- | The T (Top) row vector matrix.
476−bang :: forall e cols. (Num e, Enum e, FL cols (), Countable cols) => Matrix e cols ()
472+bang :: forall e cols. (Num e, Enum e, FromLists e cols (), Countable cols) => Matrix e cols ()
477473bang =
478474 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
479475 in fromLists [take c [1, 1 ..]]
480476
481−-- iden Matrix
477+-- Identity Matrix
482478
483−-- | iden matrix.
484−iden :: forall e cols . (Num e, FL cols cols, Countable cols) => Matrix e cols cols
485−iden = matrixBuilder' (bool 0 1 . uncurry (==))
486−{-# NOINLINE iden #-}
479+-- | Identity matrix.
480+identity :: (Num e, FromLists e cols cols, Countable cols) => Matrix e cols cols
481+identity = matrixBuilder (bool 0 1 . uncurry (==))
482+{-# NOINLINE identity #-}
487483
488484-- Matrix composition (MMM)
489485
@@ -492,90 +488,65 @@ iden = matrixBuilder' (bool 0 1 . uncurry (==))
492488-- This definition takes advantage of divide-and-conquer and fusion laws
493489-- from LAoP.
494490comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
495−comp (One a) (One b) = One (a * b)
496−comp (Join a b) (Fork c d) = comp a c + comp b d -- Divide-and-conquer law
497−comp (Fork a b) c = Fork (comp a c) (comp b c) -- Fork fusion law
498−comp c (Join a b) = Join (comp c a) (comp c b) -- Join fusion law
491+comp Empty Empty = Empty
492+comp (One a) (One b) = One (a * b)
493+comp (Junc a b) (Split c d) = comp a c + comp b d -- Divide-and-conquer law
494+comp (Split a b) c = Split (comp a c) (comp b c) -- Split fusion law
495+comp c (Junc a b) = Junc (comp c a) (comp c b) -- Junc fusion law
499496{-# NOINLINE comp #-}
500−{-# RULES
501− "comp/iden1" forall m. comp m iden = m ;
502− "comp/iden2" forall m. comp iden m = m
497+{-# RULES
498+ "comp/identity1" forall m. comp m identity = m ;
499+ "comp/identity2" forall m. comp identity m = m
503500#-}
504501
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−
523502-- Projections
524503
525504-- | Biproduct first component projection
526−p1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e (Either m n) m
527−p1 = join id zeros
505+p1 :: forall e m n. (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e (Either m n) m
506+p1 =
507+ let iden = identity :: Matrix e m m
508+ zero = zeros :: Matrix e n m
509+ in junc iden zero
528510
529511-- | Biproduct second component projection
530−p2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e (Either m n) n
531−p2 = join zeros id
512+p2 :: forall e m n. (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e (Either m n) n
513+p2 =
514+ let iden = identity :: Matrix e n n
515+ zero = zeros :: Matrix e m n
516+ in junc zero iden
532517
533518-- Injections
534519
535520-- | Biproduct first component injection
536−i1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e m (Either m n)
521+i1 :: (Num e, CountableDimensions n m, FromLists e n m, FromLists e m m) => Matrix e m (Either m n)
537522i1 = tr p1
538523
539524-- | Biproduct second component injection
540−i2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e n (Either m n)
525+i2 :: (Num e, CountableDimensions n m, FromLists e m n, FromLists e n n) => Matrix e n (Either m n)
541526i2 = tr p2
542527
543528-- Dimensions
544529
545530-- | Obtain the number of rows.
546531--
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''.
532+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
533+-- dimensions in constant time.
534+--
535+-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
536+-- exchange for performance.
550537rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
551538rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
552539
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−
562540-- | Obtain the number of columns.
541+--
542+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
543+-- dimensions in constant time.
563544--
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''.
545+-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
546+-- exchange for performance.
567547columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
568548columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
569549
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−
579550-- Coproduct Bifunctor
580551
581552infixl 5 -|-
@@ -584,161 +555,164 @@ infixl 5 -|-
584555(-|-) ::
585556 forall e n k m j.
586557 ( Num e,
587− CountableDims j k,
588− FL k k,
589− FL j k,
590− FL k j,
591− FL j j
558+ CountableDimensions j k,
559+ FromLists e k k,
560+ FromLists e j k,
561+ FromLists e k j,
562+ FromLists e j j
592563 ) =>
593564 Matrix e n k ->
594565 Matrix e m j ->
595566 Matrix e (Either n m) (Either k j)
596−(-|-) a b = Join (i1 . a) (i2 . b)
567+(-|-) a b = Junc (i1 . a) (i2 . b)
597568
598569-- Khatri Rao Product and projections
599570
600571-- | Khatri Rao product first component projection matrix.
601−fstM ::
572+kp1 ::
602573 forall e m k .
603574 ( Num e,
604− CountableDims k m,
605− FL (Normalize (m, k)) m,
575+ CountableDimensions k m,
576+ FromLists e (Normalize (m, k)) m,
606577 CountableN (m, k)
607578 ) => Matrix e (Normalize (m, k)) m
608−fstM = matrixBuilder' f
579+kp1 = matrixBuilder f
609580 where
610581 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
611582 f (x, y)
612583 | y >= (x * offset) && y <= (x * offset + offset - 1) = 1
613− | otherwise = 0
584+ | otherwise = 0
614585
615586-- | Khatri Rao product second component projection matrix.
616−sndM ::
587+kp2 ::
617588 forall e m k .
618589 ( Num e,
619− CountableDims k m,
620− FL (Normalize (m, k)) k,
590+ CountableDimensions k m,
591+ FromLists e (Normalize (m, k)) k,
621592 CountableN (m, k)
622593 ) => Matrix e (Normalize (m, k)) k
623−sndM = matrixBuilder' f
594+kp2 = matrixBuilder f
624595 where
625596 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
626597 f (x, y)
627598 | x == y || mod (y - x) offset == 0 = 1
628− | otherwise = 0
599+ | otherwise = 0
629600
630601-- | Khatri Rao Matrix product also known as matrix pairing.
631602--
632603-- NOTE: That this is not a true categorical product, see for instance:
633−--
604+--
634605-- @
635−-- | fstM . kr a b == a
636−-- kr a b ==> |
637−-- | sndM . kr a b == b
606+-- | kp1 . khatri a b == a
607+-- khatri a b ==> |
608+-- | kp2 . khatri a b == b
638609-- @
639610--
640611-- __Emphasis__ on the implication symbol.
641−kr ::
642− forall e cols a b.
612+khatri ::
613+ forall e cols a b.
643614 ( Num e,
644− CountableDims a b,
615+ CountableDimensions a b,
645616 CountableN (a, b),
646− FL (Normalize (a, b)) a,
647− FL (Normalize (a, b)) b
617+ FromLists e (Normalize (a, b)) a,
618+ FromLists e (Normalize (a, b)) b
648619 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
649−kr a b =
650− let fstM' = fstM @e @a @b
651− sndM' = sndM @e @a @b
652− in (tr fstM' . a) * (tr sndM' . b)
620+khatri a b =
621+ let kp1' = kp1 @e @a @b
622+ kp2' = kp2 @e @a @b
623+ in (tr kp1') . a * (tr kp2') . b
653624
654625-- Product Bifunctor (Kronecker)
655626
656627infixl 4 ><
657628
658629-- | Matrix product functor also known as kronecker product
659−(><) ::
660− forall e m p n q.
630+(><) ::
631+ forall e m p n q.
661632 ( Num e,
662− CountableDims m n,
663− CountableDims p q,
664− CountableDimsN (m, n) (p, q),
665− FL (Normalize (m, n)) m,
666− FL (Normalize (m, n)) n,
667− FL (Normalize (p, q)) p,
668− FL (Normalize (p, q)) q
669− )
633+ CountableDimensions m n,
634+ CountableDimensions p q,
635+ CountableDimensionsN (m, n) (p, q),
636+ FromLists e (Normalize (m, n)) m,
637+ FromLists e (Normalize (m, n)) n,
638+ FromLists e (Normalize (p, q)) p,
639+ FromLists e (Normalize (p, q)) q
640+ )
670641 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
671642(><) a b =
672− let fstM' = fstM @e @m @n
673− sndM' = sndM @e @m @n
674− in kr (a . fstM') (b . sndM')
643+ let kp1' = kp1 @e @m @n
644+ kp2' = kp2 @e @m @n
645+ in khatri (a . kp1') (b . kp2')
675646
676−-- Matrix abide Join Fork
647+-- Matrix abide Junc Split
677648
678−-- | Matrix "abiding" following the 'Join'-'Fork' exchange law.
679−--
649+-- | Matrix "abiding" followin the 'Junc'-'Split' abide law.
650+--
680651-- Law:
681652--
682653-- @
683−-- 'Join' ('Fork' a c) ('Fork' b d) == 'Fork' ('Join' a b) ('Join' c d)
654+-- 'Junc' ('Split' a c) ('Split' b d) == 'Split' ('Junc' a b) ('Junc' c d)
684655-- @
685−abideJF :: Matrix e cols rows -> Matrix e cols rows
686−abideJF (Join (Fork a c) (Fork b d)) = Fork (Join (abideJF a) (abideJF b)) (Join (abideJF c) (abideJF d)) -- Join-Fork abide law
687−abideJF (One e) = One e
688−abideJF (Join a b) = Join (abideJF a) (abideJF b)
689−abideJF (Fork a b) = Fork (abideJF a) (abideJF b)
656+abideJS :: Matrix e cols rows -> Matrix e cols rows
657+abideJS (Junc (Split a c) (Split b d)) = Split (Junc (abideJS a) (abideJS b)) (Junc (abideJS c) (abideJS d)) -- Junc-Split abide law
658+abideJS Empty = Empty
659+abideJS (One e) = One e
660+abideJS (Junc a b) = Junc (abideJS a) (abideJS b)
661+abideJS (Split a b) = Split (abideJS a) (abideJS b)
690662
691−-- Matrix abide Fork Join
663+-- Matrix abide Split Junc
692664
693−-- | Matrix "abiding" followin the 'Fork'-'Join' abide law.
694−--
665+-- | Matrix "abiding" followin the 'Split'-'Junc' abide law.
666+--
695667-- @
696−-- 'Fork' ('Join' a b) ('Join' c d) == 'Join' ('Fork' a c) ('Fork' b d)
668+-- 'Split' ('Junc' a b) ('Junc' c d) == 'Junc' ('Split' a c) ('Split' b d)
697669-- @
698−abideFJ :: Matrix e cols rows -> Matrix e cols rows
699−abideFJ (Fork (Join a b) (Join c d)) = Join (Fork (abideFJ a) (abideFJ c)) (Fork (abideFJ b) (abideFJ d)) -- Fork-Join abide law
700−abideFJ (One e) = One e
701−abideFJ (Join a b) = Join (abideFJ a) (abideFJ b)
702−abideFJ (Fork a b) = Fork (abideFJ a) (abideFJ b)
670+abideSJ :: Matrix e cols rows -> Matrix e cols rows
671+abideSJ (Split (Junc a b) (Junc c d)) = Junc (Split (abideSJ a) (abideSJ c)) (Split (abideSJ b) (abideSJ d)) -- Split-Junc abide law
672+abideSJ Empty = Empty
673+abideSJ (One e) = One e
674+abideSJ (Junc a b) = Junc (abideSJ a) (abideSJ b)
675+abideSJ (Split a b) = Split (abideSJ a) (abideSJ b)
703676
704677-- Matrix transposition
705678
706679-- | Matrix transposition.
707680tr :: Matrix e cols rows -> Matrix e rows cols
708−tr (One e) = One e
709−tr (Join a b) = Fork (tr a) (tr b)
710−tr (Fork a b) = Join (tr a) (tr b)
681+tr Empty = Empty
682+tr (One e) = One e
683+tr (Junc a b) = Split (tr a) (tr b)
684+tr (Split a b) = Junc (tr a) (tr b)
711685
712686-- Selective 'select' operator
713687
714688-- | Selective functors 'select' operator equivalent inspired by the
715689-- 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
717−select (Fork a b) y = y . a + b -- Divide-and-conquer law
718−select (Join (Fork a c) (Fork b d)) y = join (y . a + c) (y . b + d) -- Pattern matching + DnC law
719−select m y = join y id . m
690+select :: (Num e, FromLists e b b, Countable b) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
691+select (Split a b) y = y . a + b -- Divide-and-conquer law
692+select (Junc (Split a c) (Split b d)) y = junc (y . a + c) (y . b + d) -- Pattern matching + DnC law
693+select m y = junc y identity . m
720694
721695branch ::
722696 ( Num e,
723− CountableDims a b,
724− CountableDims c (Either b c),
725− FL c b,
726− FL a b,
727− FL a a,
728− FL b b,
729− FL c c,
730− FL b a,
731− FL b c,
732− FL (Either b c) b,
733− FL (Either b c) c
697+ CountableDimensions a b,
698+ CountableDimensions c (Either b c),
699+ FromLists e c b,
700+ FromLists e a b,
701+ FromLists e a a,
702+ FromLists e b b,
703+ FromLists e c c,
704+ FromLists e b a,
705+ FromLists e b c,
706+ FromLists e (Either b c) b,
707+ FromLists e (Either b c) c
734708 )
735709 => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
736710branch x l r = f x `select` g l `select` r
737711 where
738− f :: (Num e, Countable a, CountableDims b c, FL a b, FL c b, FL b b, FL b a, FL a a)
712+ 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)
739713 => Matrix e cols (Either a b) -> Matrix e cols (Either a (Either b c))
740− 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)
714+ f m = split (tr i1) (i1 . tr i2) . m
715+ g :: (Num e, CountableDimensions b c, FromLists e b c, FromLists e c c) => Matrix e a c -> Matrix e a (Either b c)
742716 g m = i2 . m
743717
744718-- McCarthy's Conditional
@@ -747,9 +721,9 @@ branch x l r = f x `select` g l `select` r
747721cond ::
748722 ( Trivial cols,
749723 Countable cols,
750− FL () cols,
751− FL cols (),
752− FL cols cols,
724+ FromLists e () cols,
725+ FromLists e cols (),
726+ FromLists e cols cols,
753727 Bounded a,
754728 Enum a,
755729 Num e,
@@ -757,14 +731,14 @@ cond ::
757731 )
758732 =>
759733 (a -> Bool) -> Matrix e cols rows -> Matrix e cols rows -> Matrix e cols rows
760−cond p f g = join f g . grd p
734+cond p f g = junc f g . grd p
761735
762−grd ::
736+grd ::
763737 ( Trivial q,
764738 Countable q,
765− FL () q,
766− FL q (),
767− FL q q,
739+ FromLists e () q,
740+ FromLists e q (),
741+ FromLists e q q,
768742 Bounded a,
769743 Enum a,
770744 Num e,
@@ -772,44 +746,44 @@ grd ::
772746 )
773747 =>
774748 (a -> Bool) -> Matrix e q (Either q q)
775−grd f = fork (corr f) (corr (not . f))
749+grd f = split (corr f) (corr (not . f))
776750
777−corr ::
778− forall e a q .
751+corr ::
752+ forall e a q .
779753 ( Trivial q,
780754 Countable q,
781− FL () q,
782− FL q (),
783− FL q q,
755+ FromLists e () q,
756+ FromLists e q (),
757+ FromLists e q q,
784758 Liftable e a Bool
785− )
759+ )
786760 => (a -> Bool) -> Matrix e q q
787−corr p = let f = fromF' p :: Matrix e q ()
788− in kr f (id :: Matrix e q q)
761+corr p = let f = fromF p :: Matrix e q ()
762+ in khatri f (identity :: Matrix e q q)
789763
790764-- Pretty print
791765
792766prettyAux :: Show e => [[e]] -> [[e]] -> String
793767prettyAux [] _ = ""
794−prettyAux [[e]] m = "│ " ++ fill (show e) ++ " │\n"
768+prettyAux [[e]] m = "│ " ++ fill (show e) ++ " │\n"
795769 where
796770 v = fmap show m
797771 widest = maximum $ fmap length v
798772 fill str = replicate (widest - length str - 2) ' ' ++ str
799−prettyAux [h] m = "│ " ++ fill (unwords $ map show h) ++ " │\n"
773+prettyAux [h] m = "│ " ++ fill (unwords $ map show h) ++ " │\n"
800774 where
801− v = fmap show m
802− widest = maximum $ fmap length v
775+ v = fmap show m
776+ widest = maximum $ fmap length v
803777 fill str = replicate (widest - length str - 2) ' ' ++ str
804−prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
778+prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
805779 prettyAux t l
806780 where
807− v = fmap show l
808− widest = maximum $ fmap length v
781+ v = fmap show l
782+ widest = maximum $ fmap length v
809783 fill str = replicate (widest - length str - 2) ' ' ++ str
810784
811785-- | Matrix pretty printer
812−pretty :: (CountableDims cols rows, Show e) => Matrix e cols rows -> String
786+pretty :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> String
813787pretty m = concat
814788 [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
815789 , unlines
@@ -817,16 +791,16 @@ pretty m = concat
817791 , "└ ", unwords (replicate (columns m) blank), " ┘"
818792 ]
819793 where
820− strings = map show (toList m)
821− widest = maximum $ map length strings
794+ strings = map show (toList m)
795+ widest = maximum $ map length strings
822796 fill str = replicate (widest - length str) ' ' ++ str
823− blank = fill ""
797+ blank = fill ""
824798 safeGet i j m
825799 | i > rows m || j > columns m || i < 1 || j < 1 = Nothing
826800 | otherwise = Just $ unsafeGet i j m (toList m)
827801 unsafeGet i j m l = l !! encode (columns m) (i,j)
828− encode m (i,j) = (i-1)*m + j - 1
829− getElem i j m =
802+ encode m (i,j) = (i-1)*m + j - 1
803+ getElem i j m =
830804 fromMaybe
831805 (error $
832806 "getElem: Trying to get the "
@@ -838,20 +812,21 @@ pretty m = concat
838812 (safeGet i j m)
839813
840814-- | Matrix pretty printer
841−prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
815+prettyPrint :: (CountableDimensions cols rows, Show e) => Matrix e cols rows -> IO ()
842816prettyPrint = putStrLn . pretty
843817
844818-- | Zip two matrices with a given binary function
845819zipWithM :: (e -> f -> g) -> Matrix e cols rows -> Matrix f cols rows -> Matrix g cols rows
846−zipWithM f (One a) (One b) = One (f a b)
847−zipWithM f (Join a b) (Join c d) = Join (zipWithM f a c) (zipWithM f b d)
848−zipWithM f (Fork a b) (Fork c d) = Fork (zipWithM f a c) (zipWithM f b d)
849−zipWithM f x@(Fork _ _) y@(Join _ _) = zipWithM f x (abideJF y)
850−zipWithM f x@(Join _ _) y@(Fork _ _) = zipWithM f (abideJF x) y
820+zipWithM f Empty Empty = Empty
821+zipWithM f (One a) (One b) = One (f a b)
822+zipWithM f (Junc a b) (Junc c d) = Junc (zipWithM f a c) (zipWithM f b d)
823+zipWithM f (Split a b) (Split c d) = Split (zipWithM f a c) (zipWithM f b d)
824+zipWithM f x@(Split _ _) y@(Junc _ _) = zipWithM f x (abideJS y)
825+zipWithM f x@(Junc _ _) y@(Split _ _) = zipWithM f (abideJS x) y
851826
852827-- Relational operators functions
853828
854−type Boolean = Natural 0 1
829+type Boolean = Natural 0 1
855830type Relation a b = Matrix Boolean a b
856831
857832-- | Helper conversion function
@@ -867,47 +842,54 @@ fromBool False = nat 0
867842
868843-- | Relational negation
869844negateM :: Relation cols rows -> Relation cols rows
870−negateM (One (Nat p)) = One (Nat (negate p))
871−negateM (Join a b) = Join (negateM a) (negateM b)
872−negateM (Fork a b) = Fork (negateM a) (negateM b)
845+negateM Empty = Empty
846+negateM (One (Nat 0)) = One (Nat 1)
847+negateM (One (Nat 1)) = One (Nat 0)
848+negateM (Junc a b) = Junc (negateM a) (negateM b)
849+negateM (Split a b) = Split (negateM a) (negateM b)
873850
874851-- | Relational addition
875852orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
876−orM (One a) (One b) = One (fromBool (toBool a || toBool b))
877−orM (Join a b) (Join c d) = Join (orM a c) (orM b d)
878−orM (Fork a b) (Fork c d) = Fork (orM a c) (orM b d)
879−orM x@(Fork _ _) y@(Join _ _) = orM x (abideJF y)
880−orM x@(Join _ _) y@(Fork _ _) = orM (abideJF x) y
853+orM Empty Empty = Empty
854+orM (One a) (One b) = One (fromBool (toBool a || toBool b))
855+orM (Junc a b) (Junc c d) = Junc (orM a c) (orM b d)
856+orM (Split a b) (Split c d) = Split (orM a c) (orM b d)
857+orM x@(Split _ _) y@(Junc _ _) = orM x (abideJS y)
858+orM x@(Junc _ _) y@(Split _ _) = orM (abideJS x) y
881859
882860-- | Relational multiplication
883861andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
884−andM (One a) (One b) = One (fromBool (toBool a && toBool b))
885−andM (Join a b) (Join c d) = Join (andM a c) (andM b d)
886−andM (Fork a b) (Fork c d) = Fork (andM a c) (andM b d)
887−andM x@(Fork _ _) y@(Join _ _) = andM x (abideJF y)
888−andM x@(Join _ _) y@(Fork _ _) = andM (abideJF x) y
862+andM Empty Empty = Empty
863+andM (One a) (One b) = One (fromBool (toBool a && toBool b))
864+andM (Junc a b) (Junc c d) = Junc (andM a c) (andM b d)
865+andM (Split a b) (Split c d) = Split (andM a c) (andM b d)
866+andM x@(Split _ _) y@(Junc _ _) = andM x (abideJS y)
867+andM x@(Junc _ _) y@(Split _ _) = andM (abideJS x) y
889868
890869-- | Relational subtraction
891870subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
892−subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
893−subM (Join a b) (Join c d) = Join (subM a c) (subM b d)
894−subM (Fork a b) (Fork c d) = Fork (subM a c) (subM b d)
895−subM x@(Fork _ _) y@(Join _ _) = subM x (abideJF y)
896−subM x@(Join _ _) y@(Fork _ _) = subM (abideJF x) y
871+subM Empty Empty = Empty
872+subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
873+subM (Junc a b) (Junc c d) = Junc (subM a c) (subM b d)
874+subM (Split a b) (Split c d) = Split (subM a c) (subM b d)
875+subM x@(Split _ _) y@(Junc _ _) = subM x (abideJS y)
876+subM x@(Junc _ _) y@(Split _ _) = subM (abideJS x) y
897877
898878-- | Matrix relational composition.
899879compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
900−compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
901−compRel (Join a b) (Fork c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
902−compRel (Fork a b) c = Fork (compRel a c) (compRel b c) -- Fork fusion law
903−compRel c (Join a b) = Join (compRel c a) (compRel c b) -- Join fusion law
880+compRel Empty Empty = Empty
881+compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
882+compRel (Junc a b) (Split c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
883+compRel (Split a b) c = Split (compRel a c) (compRel b c) -- Split fusion law
884+compRel c (Junc a b) = Junc (compRel c a) (compRel c b) -- Junc fusion law
904885
905886-- | Matrix relational right division
906887divR :: Relation b c -> Relation b a -> Relation a c
888+divR Empty Empty = Empty
907889divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
908−divR (Join a b) (Join c d) = andM (divR a c) (divR b d)
909−divR (Fork a b) c = Fork (divR a c) (divR b c)
910−divR c (Fork a b) = Join (divR c a) (divR c b)
890+divR (Junc a b) (Junc c d) = andM (divR a c) (divR b d)
891+divR (Split a b) c = Split (divR a c) (divR b c)
892+divR c (Split a b) = Junc (divR c a) (divR c b)
911893
912894-- | Matrix relational left division
913895divL :: Relation c b -> Relation a b -> Relation a c
@@ -923,52 +905,86 @@ divS s r = divL r s `intersection` divR (tr r) (tr s)
923905--
924906-- NOTE: Be careful to not ask for a relation bigger than the cardinality of
925907-- types @a@ or @b@ allows.
926−fromFRel' ::
908+fromFRel ::
927909 forall a b cols rows.
928910 ( Liftable Boolean a b,
929− CountableDims cols rows,
930− FL rows cols
911+ CountableDimensions cols rows,
912+ FromLists Boolean rows cols
931913 ) =>
932914 (a -> b) ->
933915 Relation cols rows
934−fromFRel' = fromF'
916+fromFRel f =
917+ let minA = minBound @a
918+ maxA = maxBound @a
919+ minB = minBound @b
920+ maxB = maxBound @b
921+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
922+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
923+ elementsA = take ccols [minA .. maxA]
924+ elementsB = take rrows [minB .. maxB]
925+ combinations = (,) <$> elementsA <*> elementsB
926+ combAp = map snd . sort . map (\(a, b) -> if f a == b
927+ then ((fromEnum a, fromEnum b), nat 1)
928+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
929+ mList = buildList combAp rrows
930+ in tr $ fromLists mList
931+ where
932+ buildList [] _ = []
933+ buildList l r = take r l : buildList (drop r l) r
935934
936935-- | Lifts functions to relations with dimensions matching @a@ and @b@
937936-- cardinality's.
938−fromFRel ::
937+fromFRel' ::
939938 forall a b.
940939 ( Liftable Boolean a b,
941− CountableDimsN a b,
942− FLN b a
940+ CountableDimensionsN a b,
941+ FromLists Boolean (Normalize b) (Normalize a)
943942 ) =>
944943 (a -> b) ->
945944 Relation (Normalize a) (Normalize b)
946−fromFRel = fromFRel'
945+fromFRel' f =
946+ let minA = minBound @a
947+ maxA = maxBound @a
948+ minB = minBound @b
949+ maxB = maxBound @b
950+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
951+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
952+ elementsA = take ccols [minA .. maxA]
953+ elementsB = take rrows [minB .. maxB]
954+ combinations = (,) <$> elementsA <*> elementsB
955+ combAp = map snd . sort . map (\(a, b) -> if f a == b
956+ then ((fromEnum a, fromEnum b), nat 1)
957+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
958+ mList = buildList combAp rrows
959+ in tr $ fromLists mList
960+ where
961+ buildList [] _ = []
962+ buildList l r = take r l : buildList (drop r l) r
947963
948964-- | Lifts a relation function to a Boolean Matrix
949−toRel ::
965+toRel ::
950966 forall a b.
951967 ( Bounded a,
952968 Bounded b,
953969 Enum a,
954970 Enum b,
955971 Eq b,
956− CountableDims a b,
957− FLN b a
958− )
972+ CountableDimensionsN a b,
973+ FromListsN Boolean b a
974+ )
959975 => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
960976toRel f =
961977 let minA = minBound @a
962978 maxA = maxBound @a
963979 minB = minBound @b
964980 maxB = maxBound @b
965− ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
966− rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
981+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
982+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
967983 elementsA = take ccols [minA .. maxA]
968984 elementsB = take rrows [minB .. maxB]
969985 combinations = (,) <$> elementsA <*> elementsB
970− combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
971− then ((fromEnum a, fromEnum b), nat 1)
986+ combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
987+ then ((fromEnum a, fromEnum b), nat 1)
972988 else ((fromEnum a, fromEnum b), nat 0)) $ combinations
973989 mList = buildList combAp rrows
974990 in tr $ fromLists mList