@@ -1,6 +1,4 @@
1−{-# LANGUAGE StrictData #-}
21{-# LANGUAGE TypeFamilyDependencies #-}
3−{-# LANGUAGE ConstraintKinds #-}
42{-# LANGUAGE AllowAmbiguousTypes #-}
53{-# LANGUAGE DataKinds #-}
64{-# LANGUAGE FlexibleContexts #-}
@@ -30,7 +28,7 @@
3028-- motivation behind the library, the underlying theory, and implementation details.
3129--
3230-- This module offers many of the combinators mentioned in the work of
33−-- Macedo (2012) and Oliveira (2012).
31+-- Macedo (2012) and Oliveira (2012).
3432--
3533-- This is an Internal module and it is no supposed to be imported.
3634--
@@ -43,26 +41,17 @@ module LAoP.Matrix.Internal
4341 --
4442 -- There exists two type families that make it easier to write
4543 -- matrix dimensions: 'FromNat' and 'Count'. This approach
46− -- leads to a very straightforward implementation
47− -- of LAoP combinators.
44+ -- leads to a very straightforward implementation
45+ -- of LAoP combinators.
4846
4947 -- * Type safe matrix representation
5048 Matrix (..),
5149
52− -- * Constraint type aliases
53− Countable,
54− CountableDims,
55− CountableN,
56− CountableDimsN,
57− FL,
58− FLN,
59− Liftable,
60− Trivial,
61−
6250 -- * Primitives
51+ empty,
6352 one,
64− join,
65− fork,
53+ junc,
54+ split,
6655
6756 -- * Auxiliary type families
6857 FromNat,
@@ -75,7 +64,6 @@ module LAoP.Matrix.Internal
7564 toLists,
7665 toList,
7766 matrixBuilder,
78− matrixBuilder',
7967 row,
8068 col,
8169 zeros,
@@ -86,38 +74,28 @@ module LAoP.Matrix.Internal
8674 -- * Misc
8775 -- ** Get dimensions
8876 columns,
89− columns',
9077 rows,
91− rows',
9278
9379 -- ** Matrix Transposition
9480 tr,
9581
96− -- ** Scalar multiplication/division of matrices
97− (.|),
98− (./),
99−
10082 -- ** Selective operator
101− select,
102− branch,
83+ select,
10384
10485 -- ** McCarthy's Conditional
10586 cond,
10687
10788 -- ** Matrix "abiding"
108− abideJF,
109− abideFJ,
110−
111− -- ** Zip matrices
112− zipWithM,
89+ abideJS,
90+ abideSJ,
11391
11492 -- * Biproduct approach
115− -- ** Fork
93+ -- ** Split
11694 (===),
11795 -- *** Projections
11896 p1,
11997 p2,
120− -- ** Join
98+ -- ** Junc
12199 (|||),
122100 -- *** Injections
123101 i1,
@@ -130,13 +108,12 @@ module LAoP.Matrix.Internal
130108
131109 -- | Note that given the restrictions imposed it is not possible to
132110 -- implement the standard type classes present in standard Haskell.
133−
134111 -- *** Matrix pairing projections
135− fstM,
136− sndM,
112+ kp1,
113+ kp2,
137114
138115 -- *** Matrix pairing
139− kr,
116+ khatri,
140117
141118 -- * Matrix composition and lifting
142119
@@ -144,10 +121,10 @@ module LAoP.Matrix.Internal
144121
145122 -- | Note that given the restrictions imposed it is not possible to
146123 -- implement the standard type classes present in standard Haskell.
147− iden,
124+ identity,
148125 comp,
149− fromF',
150126 fromF,
127+ fromF',
151128
152129 -- * Matrix printing
153130 pretty,
@@ -157,9 +134,6 @@ module LAoP.Matrix.Internal
157134 toBool,
158135 fromBool,
159136 compRel,
160− divR,
161− divL,
162− divS,
163137 fromFRel,
164138 fromFRel',
165139 toRel,
@@ -174,22 +148,21 @@ import LAoP.Utils.Internal
174148import Data.Bool
175149import Data.Kind
176150import Data.List
177−import Data.Maybe
178151import Data.Proxy
179−import Data.Typeable
180152import Data.Void
181153import GHC.TypeLits
182154import Data.Type.Equality
183155import GHC.Generics
184156import Control.DeepSeq
185−import Prelude hiding (id, (.))
186−import qualified Prelude (id, (.))
157+import Control.Category
158+import Prelude hiding ((.))
187159
188160-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
189161data Matrix e cols rows where
162+ Empty :: Matrix e Void Void
190163 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)
164+ Junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
165+ Split :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
193166
194167deriving instance (Show e) => Show (Matrix e cols rows)
195168
@@ -199,214 +172,221 @@ deriving instance (Show e) => Show (Matrix e cols rows)
199172-- 'Generic' instance.
200173type family Count (d :: Type) :: Nat where
201174 Count (Natural n m) = (m - n) + 1
202− Count (List a) = (^) 2 (Count a)
203− Count (Either a b) = (+) (Count a) (Count b)
204− Count (a, b) = (*) (Count a) (Count b)
205− Count (a -> b) = (^) (Count b) (Count a)
175+ Count (Either a b) = (+) (Count a) (Count b)
176+ Count (a, b) = (*) (Count a) (Count b)
177+ Count (a -> b) = (^) (Count b) (Count a)
206178 -- Generics
207− Count (M1 _ _ f p) = Count (f p)
208− Count (K1 _ _ _) = 1
209− Count (V1 _) = 0
210− Count (U1 _) = 1
179+ Count (M1 _ _ f p) = Count (f p)
180+ Count (K1 _ _ _) = 1
181+ Count (V1 _) = 0
182+ Count (U1 _) = 1
211183 Count ((:*:) a b p) = Count (a p) * Count (b p)
212184 Count ((:+:) a b p) = Count (a p) + Count (b p)
213− Count d = Count (Rep d R)
185+ Count d = Count (Rep d R)
214186
215187-- | Type family that computes of a given type dimension from a given natural
216188--
217189-- Thanks to Li-Yao Xia this type family is super fast.
218190type family FromNat (n :: Nat) :: Type where
191+ FromNat 0 = Void
219192 FromNat 1 = ()
220193 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
221194
222195type family FromNat' (b :: Bool) (m :: Type) :: Type where
223− FromNat' 'True m = Either m m
196+ FromNat' 'True m = Either m m
224197 FromNat' 'False m = Either () (Either m m)
225198
226199-- | Type family that normalizes the representation of a given data
227200-- structure
228201type family Normalize (d :: Type) :: Type where
229− Normalize (Either a b) = Either (Normalize a) (Normalize b)
230− Normalize d = FromNat (Count d)
231−
232−-- | Constraint type synonyms to keep the type signatures less convoluted
233−type Countable a = KnownNat (Count a)
234−type 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)
239−type Liftable e a b = (Bounded a, Bounded b, Enum a, Enum b, Eq b, Num e, Ord e)
240−type Trivial a = FromNat (Count a) ~ a
241−
242−-- | It is possible to implement a constrained version of the category type
243−-- class.
202+ Normalize d = FromNat (Count d)
203+
204+-- | It isn't possible to implement the 'id' function so it's
205+-- implementation is 'undefined'. However 'comp' can be and this partial
206+-- class implementation exists just to make the code more readable.
207+--
208+-- Please use 'identity' instead.
244209instance (Num e) => Category (Matrix e) where
245− type Object (Matrix e) a = (FL a a, Countable a)
246− id = iden
247− (.) = comp
210+ id = undefined
211+ (.) = comp
248212
249213instance 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
214+ rnf Empty = ()
215+ rnf (One e) = rnf e
216+ rnf (Junc a b) = rnf a `seq` rnf b
217+ rnf (Split a b) = rnf a `seq` rnf b
253218
254219instance 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
220+ Empty == Empty = True
221+ (One a) == (One b) = a == b
222+ (Junc a b) == (Junc c d) = a == c && b == d
223+ (Split a b) == (Split c d) = a == c && b == d
224+ x@(Split _ _) == y@(Junc _ _) = x == abideJS y
225+ x@(Junc _ _) == y@(Split _ _) = abideJS x == y
260226
261227instance Num e => Num (Matrix e cols rows) where
262− a + b = zipWithM (+) a b
263228
264− a - b = zipWithM (-) a b
265−
266− a * b = zipWithM (*) a b
267−
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)
271−
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)
229+ Empty + Empty = Empty
230+ (One a) + (One b) = One (a + b)
231+ (Junc a b) + (Junc c d) = Junc (a + c) (b + d)
232+ (Split a b) + (Split c d) = Split (a + c) (b + d)
233+ x@(Split _ _) + y@(Junc _ _) = x + abideJS y
234+ x@(Junc _ _) + y@(Split _ _) = abideJS x + y
235+
236+ Empty - Empty = Empty
237+ (One a) - (One b) = One (a - b)
238+ (Junc a b) - (Junc c d) = Junc (a - c) (b - d)
239+ (Split a b) - (Split c d) = Split (a - c) (b - d)
240+ x@(Split _ _) - y@(Junc _ _) = x - abideJS y
241+ x@(Junc _ _) - y@(Split _ _) = abideJS x - y
242+
243+ Empty * Empty = Empty
244+ (One a) * (One b) = One (a * b)
245+ (Junc a b) * (Junc c d) = Junc (a * c) (b * d)
246+ (Split a b) * (Split c d) = Split (a * c) (b * d)
247+ x@(Split _ _) * y@(Junc _ _) = x * abideJS y
248+ x@(Junc _ _) * y@(Split _ _) = abideJS x * y
249+
250+ abs Empty = Empty
251+ abs (One a) = One (abs a)
252+ abs (Junc a b) = Junc (abs a) (abs b)
253+ abs (Split a b) = Split (abs a) (abs b)
254+
255+ signum Empty = Empty
256+ signum (One a) = One (signum a)
257+ signum (Junc a b) = Junc (signum a) (signum b)
258+ signum (Split a b) = Split (signum a) (signum b)
275259
276260instance 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
261+ Empty <= Empty = True
262+ (One a) <= (One b) = a <= b
263+ (Junc a b) <= (Junc c d) = (a <= c) && (b <= d)
264+ (Split a b) <= (Split c d) = (a <= c) && (b <= d)
265+ x@(Split _ _) <= y@(Junc _ _) = x <= abideJS y
266+ x@(Junc _ _) <= y@(Split _ _) = abideJS x <= y
282267
283268-- Primitives
284269
270+-- | Empty matrix constructor
271+empty :: Matrix e Void Void
272+empty = Empty
273+
285274-- | Unit matrix constructor
286275one :: e -> Matrix e () ()
287276one = One
288277
289−-- | Matrix 'Join' constructor
290−join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
291−join = Join
278+-- | Matrix 'Junc' constructor
279+junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
280+junc = Junc
292281
293282infixl 3 |||
294283
295−-- | Matrix 'Join' constructor
284+-- | Matrix 'Junc' constructor
296285(|||) :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
297−(|||) = Join
286+(|||) = Junc
298287
299−-- | Matrix 'Fork' constructor
300−fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
301−fork = Fork
288+-- | Matrix 'Split' constructor
289+split :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
290+split = Split
302291
303292infixl 2 ===
304293
305−-- | Matrix 'Fork' constructor
294+-- | Matrix 'Split' constructor
306295(===) :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
307−(===) = Fork
296+(===) = Split
308297
309298-- Construction
310299
311300-- | Type class for defining the 'fromList' conversion function.
312301--
313302-- 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.
315−class FromLists cols rows where
303+-- classes are needed bery much like an inductive definition but on types.
304+class FromLists e cols rows where
316305 -- | Build a matrix out of a list of list of elements. Throws a runtime
317306 -- error if the dimensions do not match.
318307 fromLists :: [[e]] -> Matrix e cols rows
319308
320−instance FromLists () () where
309+instance FromLists e Void Void where
310+ fromLists [] = Empty
311+ fromLists _ = error "Wrong dimensions"
312+
313+instance {-# OVERLAPPING #-} FromLists e () () where
321314 fromLists [[e]] = One e
322315 fromLists _ = error "Wrong dimensions"
323316
324−instance (FromLists cols ()) => FromLists (Either () cols) () where
325− fromLists [h : t] = Join (One h) (fromLists [t])
317+instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
318+ fromLists [h : t] = Junc (One h) (fromLists [t])
326319 fromLists _ = error "Wrong dimensions"
327320
328−instance {-# OVERLAPPABLE #-}
329− (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
330− fromLists [l] =
321+instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), KnownNat (Count a)) => FromLists e (Either a b) () where
322+ fromLists [l] =
331323 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
332− in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
324+ in Junc (fromLists [take rowsA l]) (fromLists [drop rowsA l])
333325 fromLists _ = error "Wrong dimensions"
334326
335−instance (FromLists () rows) => FromLists () (Either () rows) where
336− fromLists ([h] : t) = Fork (One h) (fromLists t)
327+instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
328+ fromLists ([h] : t) = Split (One h) (fromLists t)
337329 fromLists _ = error "Wrong dimensions"
338330
339−instance {-# OVERLAPPABLE #-}
340− (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
341− fromLists l@([_] : _) =
331+instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, KnownNat (Count a)) => FromLists e () (Either a b) where
332+ fromLists l@([_] : _) =
342333 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
343− in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
334+ in Split (fromLists (take rowsA l)) (fromLists (drop rowsA l))
344335 fromLists _ = error "Wrong dimensions"
345336
346−instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
347− => FromLists (Either a b) (Either c d) where
337+instance {-# OVERLAPPABLE #-} (FromLists e (Either a b) c, FromLists e (Either a b) d, KnownNat (Count c)) => FromLists e (Either a b) (Either c d) where
348338 fromLists l@(h : t) =
349339 let lh = length h
350340 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
351− condition = all ((== lh) . length) t
341+ condition = all (== lh) (map length t)
352342 in if lh > 0 && condition
353− then Fork (fromLists (take rowsC l)) (fromLists (drop rowsC l))
343+ then Split (fromLists (take rowsC l)) (fromLists (drop rowsC l))
354344 else error "Not all rows have the same length"
355345
356346-- | Matrix builder function. Constructs a matrix provided with
357−-- a construction function that operates with indices.
358−matrixBuilder' ::
347+-- a construction function.
348+matrixBuilder ::
359349 forall e cols rows.
360− ( FL cols rows,
361− CountableDims cols rows
362− ) => ((Int, Int) -> e) -> Matrix e cols rows
363−matrixBuilder' f =
350+ ( FromLists e cols rows,
351+ KnownNat (Count cols),
352+ KnownNat (Count rows)
353+ ) =>
354+ ((Int, Int) -> e) ->
355+ Matrix e cols rows
356+matrixBuilder f =
364357 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
365358 r = fromInteger $ natVal (Proxy :: Proxy (Count rows))
366359 positions = [(a, b) | a <- [0 .. (r - 1)], b <- [0 .. (c - 1)]]
367360 in fromLists . map (map f) . groupBy (\(x, _) (w, _) -> x == w) $ positions
368361
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−
389362-- | Constructs a column vector matrix
390−col :: (FL () rows) => [e] -> Matrix e () rows
363+col :: (FromLists e () rows) => [e] -> Matrix e () rows
391364col = fromLists . map (: [])
392365
393366-- | Constructs a row vector matrix
394−row :: (FL cols ()) => [e] -> Matrix e cols ()
367+row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
395368row = fromLists . (: [])
396369
397370-- | Lifts functions to matrices with arbitrary dimensions.
398371--
399372-- NOTE: Be careful to not ask for a matrix bigger than the cardinality of
400373-- types @a@ or @b@ allows.
401−fromF' ::
374+fromF ::
402375 forall a b cols rows e.
403− ( Liftable e a b,
404− CountableDims cols rows,
405− FL rows cols
376+ ( Bounded a,
377+ Bounded b,
378+ Enum a,
379+ Enum b,
380+ Eq b,
381+ Num e,
382+ Ord e,
383+ KnownNat (Count cols),
384+ KnownNat (Count rows),
385+ FromLists e rows cols
406386 ) =>
407387 (a -> b) ->
408388 Matrix e cols rows
409−fromF' f =
389+fromF f =
410390 let minA = minBound @a
411391 maxA = maxBound @a
412392 minB = minBound @b
@@ -416,8 +396,8 @@ fromF' f =
416396 elementsA = take ccols [minA .. maxA]
417397 elementsB = take rrows [minB .. maxB]
418398 combinations = (,) <$> elementsA <*> elementsB
419− combAp = map snd . sort . map (\(a, b) -> if f a == b
420− then ((fromEnum a, fromEnum b), 1)
399+ combAp = map snd . sort . map (\(a, b) -> if f a == b
400+ then ((fromEnum a, fromEnum b), 1)
421401 else ((fromEnum a, fromEnum b), 0)) $ combinations
422402 mList = buildList combAp rrows
423403 in tr $ fromLists mList
@@ -427,23 +407,48 @@ fromF' f =
427407
428408-- | Lifts functions to matrices with dimensions matching @a@ and @b@
429409-- cardinality's.
430−fromF ::
410+fromF' ::
431411 forall a b e.
432− ( Liftable e a b,
433− CountableDimsN a b,
434− FLN b a
412+ ( Bounded a,
413+ Bounded b,
414+ Enum a,
415+ Enum b,
416+ Eq b,
417+ Num e,
418+ Ord e,
419+ KnownNat (Count (Normalize a)),
420+ KnownNat (Count (Normalize b)),
421+ FromLists e (Normalize b) (Normalize a)
435422 ) =>
436423 (a -> b) ->
437424 Matrix e (Normalize a) (Normalize b)
438−fromF = fromF'
425+fromF' f =
426+ let minA = minBound @a
427+ maxA = maxBound @a
428+ minB = minBound @b
429+ maxB = maxBound @b
430+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
431+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
432+ elementsA = take ccols [minA .. maxA]
433+ elementsB = take rrows [minB .. maxB]
434+ combinations = (,) <$> elementsA <*> elementsB
435+ combAp = map snd . sort . map (\(a, b) -> if f a == b
436+ then ((fromEnum a, fromEnum b), 1)
437+ else ((fromEnum a, fromEnum b), 0)) $ combinations
438+ mList = buildList combAp rrows
439+ in tr $ fromLists mList
440+ where
441+ buildList [] _ = []
442+ buildList l r = take r l : buildList (drop r l) r
439443
440444-- Conversion
441445
442446-- | Converts a matrix to a list of lists of elements.
443447toLists :: Matrix e cols rows -> [[e]]
448+toLists Empty = []
444449toLists (One e) = [[e]]
445−toLists (Fork l r) = toLists l ++ toLists r
446−toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
450+toLists (Split l r) = toLists l ++ toLists r
451+toLists (Junc l r) = zipWith (++) (toLists l) (toLists r)
447452
448453-- | Converts a matrix to a list of elements.
449454toList :: Matrix e cols rows -> [e]
@@ -452,38 +457,37 @@ toList = concat . toLists
452457-- Zeros Matrix
453458
454459-- | 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)
460+zeros :: (Num e, FromLists e cols rows, KnownNat (Count cols), KnownNat (Count rows)) => Matrix e cols rows
461+zeros = matrixBuilder (const 0)
457462
458463-- Ones Matrix
459464
460465-- | The ones matrix. A matrix wholly filled with ones.
461466--
462467-- 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)
468+ones :: (Num e, FromLists e cols rows, KnownNat (Count cols), KnownNat (Count rows)) => Matrix e cols rows
469+ones = matrixBuilder (const 1)
465470
466471-- Const Matrix
467472
468473-- | The constant matrix constructor. A matrix wholly filled with a given
469474-- value.
470−constant :: (Num e, FL cols rows, CountableDims cols rows) => e -> Matrix e cols rows
471−constant e = matrixBuilder' (const e)
475+constant :: (Num e, FromLists e cols rows, KnownNat (Count cols), KnownNat (Count rows)) => e -> Matrix e cols rows
476+constant e = matrixBuilder (const e)
472477
473478-- Bang Matrix
474479
475480-- | The T (Top) row vector matrix.
476−bang :: forall e cols. (Num e, Enum e, FL cols (), Countable cols) => Matrix e cols ()
481+bang :: forall e cols. (Num e, Enum e, FromLists e cols (), KnownNat (Count cols)) => Matrix e cols ()
477482bang =
478483 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
479484 in fromLists [take c [1, 1 ..]]
480485
481−-- iden Matrix
486+-- Identity Matrix
482487
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 #-}
488+-- | Identity matrix.
489+identity :: (Num e, FromLists e cols cols, KnownNat (Count cols)) => Matrix e cols cols
490+identity = matrixBuilder (bool 0 1 . uncurry (==))
487491
488492-- Matrix composition (MMM)
489493
@@ -492,90 +496,60 @@ iden = matrixBuilder' (bool 0 1 . uncurry (==))
492496-- This definition takes advantage of divide-and-conquer and fusion laws
493497-- from LAoP.
494498comp :: (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
499−{-# NOINLINE comp #-}
500−{-# RULES
501− "comp/iden1" forall m. comp m iden = m ;
502− "comp/iden2" forall m. comp iden m = m
503−#-}
504−
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)
499+comp Empty Empty = Empty
500+comp (One a) (One b) = One (a * b)
501+comp (Junc a b) (Split c d) = comp a c + comp b d -- Divide-and-conquer law
502+comp (Split a b) c = Split (comp a c) (comp b c) -- Split fusion law
503+comp c (Junc a b) = Junc (comp c a) (comp c b) -- Junc fusion law
522504
523505-- Projections
524506
525507-- | 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
508+p1 :: forall e m n. (Num e, KnownNat (Count n), KnownNat (Count m), FromLists e n m, FromLists e m m) => Matrix e (Either m n) m
509+p1 =
510+ let iden = identity :: Matrix e m m
511+ zero = zeros :: Matrix e n m
512+ in junc iden zero
528513
529514-- | 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
515+p2 :: forall e m n. (Num e, KnownNat (Count n), KnownNat (Count m), FromLists e m n, FromLists e n n) => Matrix e (Either m n) n
516+p2 =
517+ let iden = identity :: Matrix e n n
518+ zero = zeros :: Matrix e m n
519+ in junc zero iden
532520
533521-- Injections
534522
535523-- | Biproduct first component injection
536−i1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e m (Either m n)
524+i1 :: (Num e, KnownNat (Count n), KnownNat (Count m), FromLists e n m, FromLists e m m) => Matrix e m (Either m n)
537525i1 = tr p1
538526
539527-- | Biproduct second component injection
540−i2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e n (Either m n)
528+i2 :: (Num e, KnownNat (Count n), KnownNat (Count m), FromLists e m n, FromLists e n n) => Matrix e n (Either m n)
541529i2 = tr p2
542530
543531-- Dimensions
544532
545533-- | Obtain the number of rows.
546534--
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''.
550−rows :: forall e cols rows. (Countable rows) => Matrix e cols rows -> Int
551−rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
552−
553−-- | Obtain the number of rows in an inefficient manner, but without any
554−-- constraints.
535+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
536+-- dimensions in constant time.
555537--
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
538+-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
539+-- exchange for performance.
540+rows :: forall e cols rows. (KnownNat (Count rows)) => Matrix e cols rows -> Int
541+rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
561542
562543-- | Obtain the number of columns.
544+--
545+-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
546+-- dimensions in constant time.
563547--
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''.
567−columns :: forall e cols rows. (Countable cols) => Matrix e cols rows -> Int
548+-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
549+-- exchange for performance.
550+columns :: forall e cols rows. (KnownNat (Count cols)) => Matrix e cols rows -> Int
568551columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
569552
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−
579553-- Coproduct Bifunctor
580554
581555infixl 5 -|-
@@ -584,172 +558,157 @@ infixl 5 -|-
584558(-|-) ::
585559 forall e n k m j.
586560 ( Num e,
587− CountableDims j k,
588− FL k k,
589− FL j k,
590− FL k j,
591− FL j j
561+ KnownNat (Count j),
562+ KnownNat (Count k),
563+ FromLists e k k,
564+ FromLists e j k,
565+ FromLists e k j,
566+ FromLists e j j
592567 ) =>
593568 Matrix e n k ->
594569 Matrix e m j ->
595570 Matrix e (Either n m) (Either k j)
596−(-|-) a b = Join (i1 . a) (i2 . b)
571+(-|-) a b = Junc (i1 . a) (i2 . b)
597572
598573-- Khatri Rao Product and projections
599574
600575-- | Khatri Rao product first component projection matrix.
601−fstM ::
576+kp1 ::
602577 forall e m k .
603578 ( Num e,
604− CountableDims k m,
605− FL (Normalize (m, k)) m,
606− CountableN (m, k)
579+ KnownNat (Count k),
580+ FromLists e (FromNat (Count m * Count k)) m,
581+ KnownNat (Count m),
582+ KnownNat (Count (Normalize (m, k)))
607583 ) => Matrix e (Normalize (m, k)) m
608−fstM = matrixBuilder' f
584+kp1 = matrixBuilder f
609585 where
610586 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
611587 f (x, y)
612588 | y >= (x * offset) && y <= (x * offset + offset - 1) = 1
613− | otherwise = 0
589+ | otherwise = 0
614590
615591-- | Khatri Rao product second component projection matrix.
616−sndM ::
592+kp2 ::
617593 forall e m k .
618594 ( Num e,
619− CountableDims k m,
620− FL (Normalize (m, k)) k,
621− CountableN (m, k)
595+ KnownNat (Count k),
596+ FromLists e (FromNat (Count m * Count k)) k,
597+ KnownNat (Count m),
598+ KnownNat (Count (Normalize (m, k)))
622599 ) => Matrix e (Normalize (m, k)) k
623−sndM = matrixBuilder' f
600+kp2 = matrixBuilder f
624601 where
625602 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
626603 f (x, y)
627604 | x == y || mod (y - x) offset == 0 = 1
628− | otherwise = 0
605+ | otherwise = 0
629606
630607-- | Khatri Rao Matrix product also known as matrix pairing.
631608--
632609-- NOTE: That this is not a true categorical product, see for instance:
633−--
610+--
634611-- @
635−-- | fstM . kr a b == a
636−-- kr a b ==> |
637−-- | sndM . kr a b == b
612+-- | kp1 . khatri a b == a
613+-- khatri a b ==> |
614+-- | kp2 . khatri a b == b
638615-- @
639616--
640617-- __Emphasis__ on the implication symbol.
641−kr ::
642− forall e cols a b.
618+khatri ::
619+ forall e cols a b.
643620 ( Num e,
644− CountableDims a b,
645− CountableN (a, b),
646− FL (Normalize (a, b)) a,
647− FL (Normalize (a, b)) b
621+ KnownNat (Count a),
622+ KnownNat (Count b),
623+ KnownNat (Count (Normalize (a, b))),
624+ FromLists e (Normalize (a, b)) a,
625+ FromLists e (Normalize (a, b)) b
648626 ) => 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)
627+khatri a b =
628+ let kp1' = kp1 @e @a @b
629+ kp2' = kp2 @e @a @b
630+ in (tr kp1') . a * (tr kp2') . b
653631
654632-- Product Bifunctor (Kronecker)
655633
656634infixl 4 ><
657635
658636-- | Matrix product functor also known as kronecker product
659−(><) ::
660− forall e m p n q.
637+(><) ::
638+ forall e m p n q.
661639 ( 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− )
640+ KnownNat (Count m),
641+ KnownNat (Count n),
642+ KnownNat (Count p),
643+ KnownNat (Count q),
644+ KnownNat (Count (Normalize (m, n))),
645+ FromLists e (Normalize (m, n)) m,
646+ FromLists e (Normalize (m, n)) n,
647+ KnownNat (Count (Normalize (p, q))),
648+ FromLists e (Normalize (p, q)) p,
649+ FromLists e (Normalize (p, q)) q
650+ )
670651 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
671652(><) a b =
672− let fstM' = fstM @e @m @n
673− sndM' = sndM @e @m @n
674− in kr (a . fstM') (b . sndM')
653+ let kp1' = kp1 @e @m @n
654+ kp2' = kp2 @e @m @n
655+ in khatri (a . kp1') (b . kp2')
675656
676−-- Matrix abide Join Fork
657+-- Matrix abide Junc Split
677658
678−-- | Matrix "abiding" following the 'Join'-'Fork' exchange law.
679−--
659+-- | Matrix "abiding" followin the 'Junc'-'Split' abide law.
660+--
680661-- Law:
681662--
682663-- @
683−-- 'Join' ('Fork' a c) ('Fork' b d) == 'Fork' ('Join' a b) ('Join' c d)
664+-- 'Junc' ('Split' a c) ('Split' b d) == 'Split' ('Junc' a b) ('Junc' c d)
684665-- @
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)
666+abideJS :: Matrix e cols rows -> Matrix e cols rows
667+abideJS (Junc (Split a c) (Split b d)) = Split (Junc (abideJS a) (abideJS b)) (Junc (abideJS c) (abideJS d)) -- Junc-Split abide law
668+abideJS Empty = Empty
669+abideJS (One e) = One e
670+abideJS (Junc a b) = Junc (abideJS a) (abideJS b)
671+abideJS (Split a b) = Split (abideJS a) (abideJS b)
690672
691−-- Matrix abide Fork Join
673+-- Matrix abide Split Junc
692674
693−-- | Matrix "abiding" followin the 'Fork'-'Join' abide law.
694−--
675+-- | Matrix "abiding" followin the 'Split'-'Junc' abide law.
676+--
695677-- @
696−-- 'Fork' ('Join' a b) ('Join' c d) == 'Join' ('Fork' a c) ('Fork' b d)
678+-- 'Split' ('Junc' a b) ('Junc' c d) == 'Junc' ('Split' a c) ('Split' b d)
697679-- @
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)
680+abideSJ :: Matrix e cols rows -> Matrix e cols rows
681+abideSJ (Split (Junc a b) (Junc c d)) = Junc (Split (abideSJ a) (abideSJ c)) (Split (abideSJ b) (abideSJ d)) -- Split-Junc abide law
682+abideSJ Empty = Empty
683+abideSJ (One e) = One e
684+abideSJ (Junc a b) = Junc (abideSJ a) (abideSJ b)
685+abideSJ (Split a b) = Split (abideSJ a) (abideSJ b)
703686
704687-- Matrix transposition
705688
706689-- | Matrix transposition.
707690tr :: 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)
691+tr Empty = Empty
692+tr (One e) = One e
693+tr (Junc a b) = Split (tr a) (tr b)
694+tr (Split a b) = Junc (tr a) (tr b)
711695
712696-- Selective 'select' operator
713697
714698-- | Selective functors 'select' operator equivalent inspired by the
715699-- 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
720−
721−branch ::
722− ( 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
734− )
735− => Matrix e cols (Either a b) -> Matrix e a c -> Matrix e b c -> Matrix e cols c
736−branch x l r = f x `select` g l `select` r
737− 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)
739− => 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)
742− g m = i2 . m
700+select :: (Num e, FromLists e b b, KnownNat (Count b)) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
701+select m y = junc y identity . m
743702
744703-- McCarthy's Conditional
745704
746705-- | McCarthy's Conditional expresses probabilistic choice.
747706cond ::
748− ( Trivial cols,
749− Countable cols,
750− FL () cols,
751− FL cols (),
752− FL cols cols,
707+ ( cols ~ FromNat (Count cols),
708+ KnownNat (Count cols),
709+ FromLists e () cols,
710+ FromLists e cols (),
711+ FromLists e cols cols,
753712 Bounded a,
754713 Enum a,
755714 Num e,
@@ -757,14 +716,14 @@ cond ::
757716 )
758717 =>
759718 (a -> Bool) -> Matrix e cols rows -> Matrix e cols rows -> Matrix e cols rows
760−cond p f g = join f g . grd p
761−
762−grd ::
763− ( Trivial q,
764− Countable q,
765− FL () q,
766− FL q (),
767− FL q q,
719+cond p f g = junc f g . grd p
720+
721+grd ::
722+ ( q ~ FromNat (Count q),
723+ KnownNat (Count q),
724+ FromLists e () q,
725+ FromLists e q (),
726+ FromLists e q q,
768727 Bounded a,
769728 Enum a,
770729 Num e,
@@ -772,88 +731,62 @@ grd ::
772731 )
773732 =>
774733 (a -> Bool) -> Matrix e q (Either q q)
775−grd f = fork (corr f) (corr (not . f))
776−
777−corr ::
778− forall e a q .
779− ( Trivial q,
780− Countable q,
781− FL () q,
782− FL q (),
783− FL q q,
784− Liftable e a Bool
785− )
734+grd f = split (corr f) (corr (not . f))
735+
736+corr ::
737+ forall e a q .
738+ ( q ~ FromNat (Count q),
739+ KnownNat (Count q),
740+ FromLists e () q,
741+ FromLists e q (),
742+ FromLists e q q,
743+ Bounded a,
744+ Enum a,
745+ Num e,
746+ Ord e
747+ )
786748 => (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)
749+corr p = let f = fromF p :: Matrix e q ()
750+ in khatri f (identity :: Matrix e q q)
789751
790752-- Pretty print
791753
792754prettyAux :: Show e => [[e]] -> [[e]] -> String
793755prettyAux [] _ = ""
794−prettyAux [[e]] m = "│ " ++ fill (show e) ++ " │\n"
756+prettyAux [[e]] m = "│ " ++ fill (show e) ++ " │\n"
795757 where
796758 v = fmap show m
797759 widest = maximum $ fmap length v
798760 fill str = replicate (widest - length str - 2) ' ' ++ str
799−prettyAux [h] m = "│ " ++ fill (unwords $ map show h) ++ " │\n"
761+prettyAux [h] m = "│ " ++ fill (unwords $ map show h) ++ " │\n"
800762 where
801− v = fmap show m
802− widest = maximum $ fmap length v
763+ v = fmap show m
764+ widest = maximum $ fmap length v
803765 fill str = replicate (widest - length str - 2) ' ' ++ str
804−prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
766+prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
805767 prettyAux t l
806768 where
807− v = fmap show l
808− widest = maximum $ fmap length v
769+ v = fmap show l
770+ widest = maximum $ fmap length v
809771 fill str = replicate (widest - length str - 2) ' ' ++ str
810772
811773-- | Matrix pretty printer
812−pretty :: (CountableDims cols rows, Show e) => Matrix e cols rows -> String
813−pretty m = concat
814− [ "┌ ", unwords (replicate (columns m) blank), " ┐\n"
815− , unlines
816− [ "│ " ++ unwords (fmap (\j -> fill $ show $ getElem i j m) [1..columns m]) ++ " │" | i <- [1..rows m] ]
817− , "└ ", unwords (replicate (columns m) blank), " ┘"
818− ]
819− where
820− strings = map show (toList m)
821− widest = maximum $ map length strings
774+pretty :: (KnownNat (Count cols), Show e) => Matrix e cols rows -> String
775+pretty m = "┌ " ++ unwords (replicate (columns m) blank) ++ " ┐\n" ++
776+ prettyAux (toLists m) (toLists m) ++
777+ "└ " ++ unwords (replicate (columns m) blank) ++ " ┘"
778+ where
779+ v = fmap show (toList m)
780+ widest = maximum $ fmap length v
822781 fill str = replicate (widest - length str) ' ' ++ str
823− blank = fill ""
824− safeGet i j m
825− | i > rows m || j > columns m || i < 1 || j < 1 = Nothing
826− | otherwise = Just $ unsafeGet i j m (toList m)
827− 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 =
830− fromMaybe
831− (error $
832− "getElem: Trying to get the "
833− ++ show (i, j)
834− ++ " element from a "
835− ++ show (rows m) ++ "x" ++ show (columns m)
836− ++ " matrix."
837− )
838− (safeGet i j m)
782+ blank = fill ""
839783
840784-- | Matrix pretty printer
841−prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
785+prettyPrint :: (KnownNat (Count cols), Show e) => Matrix e cols rows -> IO ()
842786prettyPrint = putStrLn . pretty
843787
844−-- | Zip two matrices with a given binary function
845−zipWithM :: (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
851−
852788-- Relational operators functions
853789
854−type Boolean = Natural 0 1
855−type Relation a b = Matrix Boolean a b
856−
857790-- | Helper conversion function
858791toBool :: (Num e, Eq e) => e -> Bool
859792toBool n
@@ -866,109 +799,143 @@ fromBool True = nat 1
866799fromBool False = nat 0
867800
868801-- | Relational negation
869−negateM :: 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)
802+negateM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
803+negateM Empty = Empty
804+negateM (One (Nat 0)) = One (Nat 1)
805+negateM (One (Nat 1)) = One (Nat 0)
806+negateM (Junc a b) = Junc (negateM a) (negateM b)
807+negateM (Split a b) = Split (negateM a) (negateM b)
873808
874809-- | Relational addition
875−orM :: 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
810+orM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
811+orM Empty Empty = Empty
812+orM (One a) (One b) = One (fromBool (toBool a || toBool b))
813+orM (Junc a b) (Junc c d) = Junc (orM a c) (orM b d)
814+orM (Split a b) (Split c d) = Split (orM a c) (orM b d)
815+orM x@(Split _ _) y@(Junc _ _) = orM x (abideJS y)
816+orM x@(Junc _ _) y@(Split _ _) = orM (abideJS x) y
881817
882818-- | Relational multiplication
883−andM :: 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
819+andM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
820+andM Empty Empty = Empty
821+andM (One a) (One b) = One (fromBool (toBool a && toBool b))
822+andM (Junc a b) (Junc c d) = Junc (andM a c) (andM b d)
823+andM (Split a b) (Split c d) = Split (andM a c) (andM b d)
824+andM x@(Split _ _) y@(Junc _ _) = andM x (abideJS y)
825+andM x@(Junc _ _) y@(Split _ _) = andM (abideJS x) y
889826
890827-- | Relational subtraction
891−subM :: 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
828+subM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
829+subM Empty Empty = Empty
830+subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
831+subM (Junc a b) (Junc c d) = Junc (subM a c) (subM b d)
832+subM (Split a b) (Split c d) = Split (subM a c) (subM b d)
833+subM x@(Split _ _) y@(Junc _ _) = subM x (abideJS y)
834+subM x@(Junc _ _) y@(Split _ _) = subM (abideJS x) y
897835
898836-- | Matrix relational composition.
899−compRel :: 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
904−
905−-- | Matrix relational right division
906−divR :: Relation b c -> Relation b a -> Relation a c
907−divR (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)
911−
912−-- | Matrix relational left division
913−divL :: Relation c b -> Relation a b -> Relation a c
914−divL x y = tr (divR (tr y) (tr x))
915−
916−-- | Matrix relational symmetric division
917−divS :: Relation c a -> Relation b a -> Relation c b
918−divS s r = divL r s `intersection` divR (tr r) (tr s)
919− where
920− intersection = andM
837+compRel :: Matrix (Natural 0 1) cr rows -> Matrix (Natural 0 1) cols cr -> Matrix (Natural 0 1) cols rows
838+compRel Empty Empty = Empty
839+compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
840+compRel (Junc a b) (Split c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
841+compRel (Split a b) c = Split (compRel a c) (compRel b c) -- Split fusion law
842+compRel c (Junc a b) = Junc (compRel c a) (compRel c b) -- Junc fusion law
921843
922844-- | Lifts functions to relations with arbitrary dimensions.
923845--
924846-- NOTE: Be careful to not ask for a relation bigger than the cardinality of
925847-- types @a@ or @b@ allows.
926−fromFRel' ::
848+fromFRel ::
927849 forall a b cols rows.
928− ( Liftable Boolean a b,
929− CountableDims cols rows,
930− FL rows cols
850+ ( Bounded a,
851+ Bounded b,
852+ Enum a,
853+ Enum b,
854+ Eq b,
855+ KnownNat (Count cols),
856+ KnownNat (Count rows),
857+ FromLists (Natural 0 1) rows cols
931858 ) =>
932859 (a -> b) ->
933− Relation cols rows
934−fromFRel' = fromF'
860+ Matrix (Natural 0 1) cols rows
861+fromFRel f =
862+ let minA = minBound @a
863+ maxA = maxBound @a
864+ minB = minBound @b
865+ maxB = maxBound @b
866+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
867+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
868+ elementsA = take ccols [minA .. maxA]
869+ elementsB = take rrows [minB .. maxB]
870+ combinations = (,) <$> elementsA <*> elementsB
871+ combAp = map snd . sort . map (\(a, b) -> if f a == b
872+ then ((fromEnum a, fromEnum b), nat 1)
873+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
874+ mList = buildList combAp rrows
875+ in tr $ fromLists mList
876+ where
877+ buildList [] _ = []
878+ buildList l r = take r l : buildList (drop r l) r
935879
936880-- | Lifts functions to relations with dimensions matching @a@ and @b@
937881-- cardinality's.
938−fromFRel ::
882+fromFRel' ::
939883 forall a b.
940− ( Liftable Boolean a b,
941− CountableDimsN a b,
942− FLN b a
884+ ( Bounded a,
885+ Bounded b,
886+ Enum a,
887+ Enum b,
888+ Eq b,
889+ KnownNat (Count (Normalize a)),
890+ KnownNat (Count (Normalize b)),
891+ FromLists (Natural 0 1) (Normalize b) (Normalize a)
943892 ) =>
944893 (a -> b) ->
945− Relation (Normalize a) (Normalize b)
946−fromFRel = fromFRel'
894+ Matrix (Natural 0 1) (Normalize a) (Normalize b)
895+fromFRel' f =
896+ let minA = minBound @a
897+ maxA = maxBound @a
898+ minB = minBound @b
899+ maxB = maxBound @b
900+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
901+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
902+ elementsA = take ccols [minA .. maxA]
903+ elementsB = take rrows [minB .. maxB]
904+ combinations = (,) <$> elementsA <*> elementsB
905+ combAp = map snd . sort . map (\(a, b) -> if f a == b
906+ then ((fromEnum a, fromEnum b), nat 1)
907+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
908+ mList = buildList combAp rrows
909+ in tr $ fromLists mList
910+ where
911+ buildList [] _ = []
912+ buildList l r = take r l : buildList (drop r l) r
947913
948914-- | Lifts a relation function to a Boolean Matrix
949−toRel ::
915+toRel ::
950916 forall a b.
951917 ( Bounded a,
952918 Bounded b,
953919 Enum a,
954920 Enum b,
955921 Eq b,
956− CountableDims a b,
957− FLN b a
958− )
959− => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
922+ KnownNat (Count (Normalize a)),
923+ KnownNat (Count (Normalize b)),
924+ FromLists (Natural 0 1) (Normalize b) (Normalize a)
925+ )
926+ => (a -> b -> Bool) -> Matrix (Natural 0 1) (Normalize a) (Normalize b)
960927toRel f =
961928 let minA = minBound @a
962929 maxA = maxBound @a
963930 minB = minBound @b
964931 maxB = maxBound @b
965− ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
966− rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
932+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
933+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
967934 elementsA = take ccols [minA .. maxA]
968935 elementsB = take rrows [minB .. maxB]
969936 combinations = (,) <$> elementsA <*> elementsB
970− combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
971− then ((fromEnum a, fromEnum b), nat 1)
937+ combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
938+ then ((fromEnum a, fromEnum b), nat 1)
972939 else ((fromEnum a, fromEnum b), nat 0)) $ combinations
973940 mList = buildList combAp rrows
974941 in tr $ fromLists mList