@@ -1,3 +1,6 @@
1+{-# LANGUAGE StrictData #-}
2+{-# LANGUAGE TypeFamilyDependencies #-}
3+{-# LANGUAGE ConstraintKinds #-}
14{-# LANGUAGE AllowAmbiguousTypes #-}
25{-# LANGUAGE DataKinds #-}
36{-# LANGUAGE FlexibleContexts #-}
@@ -9,7 +12,6 @@
912{-# LANGUAGE ScopedTypeVariables #-}
1013{-# LANGUAGE StandaloneDeriving #-}
1114{-# LANGUAGE TypeApplications #-}
12−{-# LANGUAGE TypeFamilies #-}
1315{-# LANGUAGE TypeOperators #-}
1416{-# LANGUAGE UndecidableInstances #-}
1517
@@ -28,7 +30,7 @@
2830-- motivation behind the library, the underlying theory, and implementation details.
2931--
3032-- This module offers many of the combinators mentioned in the work of
31−-- Macedo (2012) and Oliveira (2012).
33+-- Macedo (2012) and Oliveira (2012).
3234--
3335-- This is an Internal module and it is no supposed to be imported.
3436--
@@ -41,17 +43,26 @@ module LAoP.Matrix.Internal
4143 --
4244 -- There exists two type families that make it easier to write
4345 -- matrix dimensions: 'FromNat' and 'Count'. This approach
44− -- leads to a very straightforward implementation
45− -- of LAoP combinators.
46+ -- leads to a very straightforward implementation
47+ -- of LAoP combinators.
4648
4749 -- * Type safe matrix representation
4850 Matrix (..),
4951
52+ -- * Constraint type aliases
53+ Countable,
54+ CountableDims,
55+ CountableN,
56+ CountableDimsN,
57+ FL,
58+ FLN,
59+ Liftable,
60+ Trivial,
61+
5062 -- * Primitives
51− empty,
5263 one,
53− junc,
54− split,
64+ join,
65+ fork,
5566
5667 -- * Auxiliary type families
5768 FromNat,
@@ -64,6 +75,7 @@ module LAoP.Matrix.Internal
6475 toLists,
6576 toList,
6677 matrixBuilder,
78+ matrixBuilder',
6779 row,
6880 col,
6981 zeros,
@@ -74,28 +86,38 @@ module LAoP.Matrix.Internal
7486 -- * Misc
7587 -- ** Get dimensions
7688 columns,
89+ columns',
7790 rows,
91+ rows',
7892
7993 -- ** Matrix Transposition
8094 tr,
8195
96+ -- ** Scalar multiplication/division of matrices
97+ (.|),
98+ (./),
99+
82100 -- ** Selective operator
83− select,
101+ select,
102+ branch,
84103
85104 -- ** McCarthy's Conditional
86105 cond,
87106
88107 -- ** Matrix "abiding"
89− abideJS,
90− abideSJ,
108+ abideJF,
109+ abideFJ,
110+
111+ -- ** Zip matrices
112+ zipWithM,
91113
92114 -- * Biproduct approach
93− -- ** Split
115+ -- ** Fork
94116 (===),
95117 -- *** Projections
96118 p1,
97119 p2,
98− -- ** Junc
120+ -- ** Join
99121 (|||),
100122 -- *** Injections
101123 i1,
@@ -108,12 +130,13 @@ module LAoP.Matrix.Internal
108130
109131 -- | Note that given the restrictions imposed it is not possible to
110132 -- implement the standard type classes present in standard Haskell.
133+
111134 -- *** Matrix pairing projections
112− kp1,
113− kp2,
135+ fstM,
136+ sndM,
114137
115138 -- *** Matrix pairing
116− khatri,
139+ kr,
117140
118141 -- * Matrix composition and lifting
119142
@@ -121,10 +144,10 @@ module LAoP.Matrix.Internal
121144
122145 -- | Note that given the restrictions imposed it is not possible to
123146 -- implement the standard type classes present in standard Haskell.
124− identity,
147+ iden,
125148 comp,
126− fromF,
127149 fromF',
150+ fromF,
128151
129152 -- * Matrix printing
130153 pretty,
@@ -134,34 +157,39 @@ module LAoP.Matrix.Internal
134157 toBool,
135158 fromBool,
136159 compRel,
160+ divR,
161+ divL,
162+ divS,
137163 fromFRel,
138164 fromFRel',
139165 toRel,
166+ negateM,
140167 orM,
141168 andM,
142169 subM
143170 )
144171 where
145172
146−import LAoP.Utils
173+import LAoP.Utils.Internal
147174import Data.Bool
148175import Data.Kind
149176import Data.List
177+import Data.Maybe
150178import Data.Proxy
179+import Data.Typeable
151180import Data.Void
152181import GHC.TypeLits
153182import Data.Type.Equality
154183import GHC.Generics
155184import Control.DeepSeq
156−import Control.Category
157−import Prelude hiding ((.))
185+import Prelude hiding (id, (.))
186+import qualified Prelude (id, (.))
158187
159188-- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
160189data Matrix e cols rows where
161− Empty :: Matrix e Void Void
162190 One :: e -> Matrix e () ()
163− Junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
164− Split :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
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)
165193
166194deriving instance (Show e) => Show (Matrix e cols rows)
167195
@@ -171,221 +199,214 @@ deriving instance (Show e) => Show (Matrix e cols rows)
171199-- 'Generic' instance.
172200type family Count (d :: Type) :: Nat where
173201 Count (Natural n m) = (m - n) + 1
174− Count (Either a b) = (+) (Count a) (Count b)
175− Count (a, b) = (*) (Count a) (Count b)
176− Count (a -> b) = (^) (Count b) (Count a)
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)
177206 -- Generics
178− Count (M1 _ _ f p) = Count (f p)
179− Count (K1 _ _ _) = 1
180− Count (V1 _) = 0
181− Count (U1 _) = 1
207+ Count (M1 _ _ f p) = Count (f p)
208+ Count (K1 _ _ _) = 1
209+ Count (V1 _) = 0
210+ Count (U1 _) = 1
182211 Count ((:*:) a b p) = Count (a p) * Count (b p)
183212 Count ((:+:) a b p) = Count (a p) + Count (b p)
184− Count d = Count (Rep d R)
213+ Count d = Count (Rep d R)
185214
186215-- | Type family that computes of a given type dimension from a given natural
187216--
188217-- Thanks to Li-Yao Xia this type family is super fast.
189218type family FromNat (n :: Nat) :: Type where
190− FromNat 0 = Void
191219 FromNat 1 = ()
192220 FromNat n = FromNat' (Mod n 2 == 0) (FromNat (Div n 2))
193221
194222type family FromNat' (b :: Bool) (m :: Type) :: Type where
195− FromNat' 'True m = Either m m
223+ FromNat' 'True m = Either m m
196224 FromNat' 'False m = Either () (Either m m)
197225
198226-- | Type family that normalizes the representation of a given data
199227-- structure
200228type family Normalize (d :: Type) :: Type where
201− Normalize d = FromNat (Count d)
202−
203−-- | It isn't possible to implement the 'id' function so it's
204−-- implementation is 'undefined'. However 'comp' can be and this partial
205−-- class implementation exists just to make the code more readable.
206−--
207−-- Please use 'identity' instead.
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.
208244instance (Num e) => Category (Matrix e) where
209− id = undefined
210− (.) = comp
245+ type Object (Matrix e) a = (FL a a, Countable a)
246+ id = iden
247+ (.) = comp
211248
212249instance NFData e => NFData (Matrix e cols rows) where
213− rnf Empty = ()
214− rnf (One e) = rnf e
215− rnf (Junc a b) = rnf a `seq` rnf b
216− rnf (Split a b) = rnf a `seq` rnf b
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
217253
218254instance Eq e => Eq (Matrix e cols rows) where
219− Empty == Empty = True
220− (One a) == (One b) = a == b
221− (Junc a b) == (Junc c d) = a == c && b == d
222− (Split a b) == (Split c d) = a == c && b == d
223− x@(Split _ _) == y@(Junc _ _) = x == abideJS y
224− x@(Junc _ _) == y@(Split _ _) = abideJS x == y
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
225260
226261instance Num e => Num (Matrix e cols rows) where
262+ a + b = zipWithM (+) a b
227263
228− Empty + Empty = Empty
229− (One a) + (One b) = One (a + b)
230− (Junc a b) + (Junc c d) = Junc (a + c) (b + d)
231− (Split a b) + (Split c d) = Split (a + c) (b + d)
232− x@(Split _ _) + y@(Junc _ _) = x + abideJS y
233− x@(Junc _ _) + y@(Split _ _) = abideJS x + y
234−
235− Empty - Empty = Empty
236− (One a) - (One b) = One (a - b)
237− (Junc a b) - (Junc c d) = Junc (a - c) (b - d)
238− (Split a b) - (Split c d) = Split (a - c) (b - d)
239− x@(Split _ _) - y@(Junc _ _) = x - abideJS y
240− x@(Junc _ _) - y@(Split _ _) = abideJS x - y
241−
242− Empty * Empty = Empty
243− (One a) * (One b) = One (a * b)
244− (Junc a b) * (Junc c d) = Junc (a * c) (b * d)
245− (Split a b) * (Split c d) = Split (a * c) (b * d)
246− x@(Split _ _) * y@(Junc _ _) = x * abideJS y
247− x@(Junc _ _) * y@(Split _ _) = abideJS x * y
248−
249− abs Empty = Empty
250− abs (One a) = One (abs a)
251− abs (Junc a b) = Junc (abs a) (abs b)
252− abs (Split a b) = Split (abs a) (abs b)
253−
254− signum Empty = Empty
255− signum (One a) = One (signum a)
256− signum (Junc a b) = Junc (signum a) (signum b)
257− signum (Split a b) = Split (signum a) (signum b)
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)
258275
259276instance Ord e => Ord (Matrix e cols rows) where
260− Empty <= Empty = True
261− (One a) <= (One b) = a <= b
262− (Junc a b) <= (Junc c d) = (a <= c) && (b <= d)
263− (Split a b) <= (Split c d) = (a <= c) && (b <= d)
264− x@(Split _ _) <= y@(Junc _ _) = x <= abideJS y
265− x@(Junc _ _) <= y@(Split _ _) = abideJS x <= y
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
266282
267283-- Primitives
268284
269−-- | Empty matrix constructor
270−empty :: Matrix e Void Void
271−empty = Empty
272−
273285-- | Unit matrix constructor
274286one :: e -> Matrix e () ()
275287one = One
276288
277−-- | Matrix 'Junc' constructor
278−junc :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
279−junc = Junc
289+-- | Matrix 'Join' constructor
290+join :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
291+join = Join
280292
281293infixl 3 |||
282294
283−-- | Matrix 'Junc' constructor
295+-- | Matrix 'Join' constructor
284296(|||) :: Matrix e a rows -> Matrix e b rows -> Matrix e (Either a b) rows
285−(|||) = Junc
297+(|||) = Join
286298
287−-- | Matrix 'Split' constructor
288−split :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
289−split = Split
299+-- | Matrix 'Fork' constructor
300+fork :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
301+fork = Fork
290302
291303infixl 2 ===
292304
293−-- | Matrix 'Split' constructor
305+-- | Matrix 'Fork' constructor
294306(===) :: Matrix e cols a -> Matrix e cols b -> Matrix e cols (Either a b)
295−(===) = Split
307+(===) = Fork
296308
297309-- Construction
298310
299311-- | Type class for defining the 'fromList' conversion function.
300312--
301313-- Given that it is not possible to branch on types at the term level type
302−-- classes are needed bery much like an inductive definition but on types.
303−class FromLists e cols rows where
314+-- classes are needed very much like an inductive definition but on types.
315+class FromLists cols rows where
304316 -- | Build a matrix out of a list of list of elements. Throws a runtime
305317 -- error if the dimensions do not match.
306318 fromLists :: [[e]] -> Matrix e cols rows
307319
308−instance FromLists e Void Void where
309− fromLists [] = Empty
310− fromLists _ = error "Wrong dimensions"
311−
312−instance {-# OVERLAPPING #-} FromLists e () () where
320+instance FromLists () () where
313321 fromLists [[e]] = One e
314322 fromLists _ = error "Wrong dimensions"
315323
316−instance {-# OVERLAPPING #-} (FromLists e cols ()) => FromLists e (Either () cols) () where
317− fromLists [h : t] = Junc (One h) (fromLists [t])
324+instance (FromLists cols ()) => FromLists (Either () cols) () where
325+ fromLists [h : t] = Join (One h) (fromLists [t])
318326 fromLists _ = error "Wrong dimensions"
319327
320−instance {-# OVERLAPPABLE #-} (FromLists e a (), FromLists e b (), KnownNat (Count a)) => FromLists e (Either a b) () where
321− fromLists [l] =
328+instance {-# OVERLAPPABLE #-}
329+ (FromLists a (), FromLists b (), Countable a) => FromLists (Either a b) () where
330+ fromLists [l] =
322331 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
323− in Junc (fromLists [take rowsA l]) (fromLists [drop rowsA l])
332+ in Join (fromLists [take rowsA l]) (fromLists [drop rowsA l])
324333 fromLists _ = error "Wrong dimensions"
325334
326−instance {-# OVERLAPPING #-} (FromLists e () rows) => FromLists e () (Either () rows) where
327− fromLists ([h] : t) = Split (One h) (fromLists t)
335+instance (FromLists () rows) => FromLists () (Either () rows) where
336+ fromLists ([h] : t) = Fork (One h) (fromLists t)
328337 fromLists _ = error "Wrong dimensions"
329338
330−instance {-# OVERLAPPABLE #-} (FromLists e () a, FromLists e () b, KnownNat (Count a)) => FromLists e () (Either a b) where
331− fromLists l@([_] : _) =
339+instance {-# OVERLAPPABLE #-}
340+ (FromLists () a, FromLists () b, Countable a) => FromLists () (Either a b) where
341+ fromLists l@([_] : _) =
332342 let rowsA = fromInteger (natVal (Proxy :: Proxy (Count a)))
333− in Split (fromLists (take rowsA l)) (fromLists (drop rowsA l))
343+ in Fork (fromLists (take rowsA l)) (fromLists (drop rowsA l))
334344 fromLists _ = error "Wrong dimensions"
335345
336−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
346+instance (FromLists (Either a b) c, FromLists (Either a b) d, Countable c)
347+ => FromLists (Either a b) (Either c d) where
337348 fromLists l@(h : t) =
338349 let lh = length h
339350 rowsC = fromInteger (natVal (Proxy :: Proxy (Count c)))
340− condition = all (== lh) (map length t)
351+ condition = all ((== lh) . length) t
341352 in if lh > 0 && condition
342− then Split (fromLists (take rowsC l)) (fromLists (drop rowsC l))
353+ then Fork (fromLists (take rowsC l)) (fromLists (drop rowsC l))
343354 else error "Not all rows have the same length"
344355
345356-- | Matrix builder function. Constructs a matrix provided with
346−-- a construction function.
347−matrixBuilder ::
357+-- a construction function that operates with indices.
358+matrixBuilder' ::
348359 forall e cols rows.
349− ( FromLists e cols rows,
350− KnownNat (Count cols),
351− KnownNat (Count rows)
352− ) =>
353− ((Int, Int) -> e) ->
354− Matrix e cols rows
355−matrixBuilder f =
360+ ( FL cols rows,
361+ CountableDims cols rows
362+ ) => ((Int, Int) -> e) -> Matrix e cols rows
363+matrixBuilder' f =
356364 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
357365 r = fromInteger $ natVal (Proxy :: Proxy (Count rows))
358366 positions = [(a, b) | a <- [0 .. (r - 1)], b <- [0 .. (c - 1)]]
359367 in fromLists . map (map f) . groupBy (\(x, _) (w, _) -> x == w) $ positions
360368
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+
361389-- | Constructs a column vector matrix
362−col :: (FromLists e () rows) => [e] -> Matrix e () rows
390+col :: (FL () rows) => [e] -> Matrix e () rows
363391col = fromLists . map (: [])
364392
365393-- | Constructs a row vector matrix
366−row :: (FromLists e cols ()) => [e] -> Matrix e cols ()
394+row :: (FL cols ()) => [e] -> Matrix e cols ()
367395row = fromLists . (: [])
368396
369397-- | Lifts functions to matrices with arbitrary dimensions.
370398--
371399-- NOTE: Be careful to not ask for a matrix bigger than the cardinality of
372400-- types @a@ or @b@ allows.
373−fromF ::
401+fromF' ::
374402 forall a b cols rows e.
375− ( Bounded a,
376− Bounded b,
377− Enum a,
378− Enum b,
379− Eq b,
380− Num e,
381− Ord e,
382− KnownNat (Count cols),
383− KnownNat (Count rows),
384− FromLists e rows cols
403+ ( Liftable e a b,
404+ CountableDims cols rows,
405+ FL rows cols
385406 ) =>
386407 (a -> b) ->
387408 Matrix e cols rows
388−fromF f =
409+fromF' f =
389410 let minA = minBound @a
390411 maxA = maxBound @a
391412 minB = minBound @b
@@ -395,8 +416,8 @@ fromF f =
395416 elementsA = take ccols [minA .. maxA]
396417 elementsB = take rrows [minB .. maxB]
397418 combinations = (,) <$> elementsA <*> elementsB
398− combAp = map snd . sort . map (\(a, b) -> if f a == b
399− then ((fromEnum a, fromEnum b), 1)
419+ combAp = map snd . sort . map (\(a, b) -> if f a == b
420+ then ((fromEnum a, fromEnum b), 1)
400421 else ((fromEnum a, fromEnum b), 0)) $ combinations
401422 mList = buildList combAp rrows
402423 in tr $ fromLists mList
@@ -406,48 +427,23 @@ fromF f =
406427
407428-- | Lifts functions to matrices with dimensions matching @a@ and @b@
408429-- cardinality's.
409−fromF' ::
430+fromF ::
410431 forall a b e.
411− ( Bounded a,
412− Bounded b,
413− Enum a,
414− Enum b,
415− Eq b,
416− Num e,
417− Ord e,
418− KnownNat (Count (Normalize a)),
419− KnownNat (Count (Normalize b)),
420− FromLists e (Normalize b) (Normalize a)
432+ ( Liftable e a b,
433+ CountableDimsN a b,
434+ FLN b a
421435 ) =>
422436 (a -> b) ->
423437 Matrix e (Normalize a) (Normalize b)
424−fromF' f =
425− let minA = minBound @a
426− maxA = maxBound @a
427− minB = minBound @b
428− maxB = maxBound @b
429− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
430− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
431− elementsA = take ccols [minA .. maxA]
432− elementsB = take rrows [minB .. maxB]
433− combinations = (,) <$> elementsA <*> elementsB
434− combAp = map snd . sort . map (\(a, b) -> if f a == b
435− then ((fromEnum a, fromEnum b), 1)
436− else ((fromEnum a, fromEnum b), 0)) $ combinations
437− mList = buildList combAp rrows
438− in tr $ fromLists mList
439− where
440− buildList [] _ = []
441− buildList l r = take r l : buildList (drop r l) r
438+fromF = fromF'
442439
443440-- Conversion
444441
445442-- | Converts a matrix to a list of lists of elements.
446443toLists :: Matrix e cols rows -> [[e]]
447−toLists Empty = []
448444toLists (One e) = [[e]]
449−toLists (Split l r) = toLists l ++ toLists r
450−toLists (Junc l r) = zipWith (++) (toLists l) (toLists r)
445+toLists (Fork l r) = toLists l ++ toLists r
446+toLists (Join l r) = zipWith (++) (toLists l) (toLists r)
451447
452448-- | Converts a matrix to a list of elements.
453449toList :: Matrix e cols rows -> [e]
@@ -456,37 +452,38 @@ toList = concat . toLists
456452-- Zeros Matrix
457453
458454-- | The zero matrix. A matrix wholly filled with zeros.
459−zeros :: (Num e, FromLists e cols rows, KnownNat (Count cols), KnownNat (Count rows)) => Matrix e cols rows
460−zeros = matrixBuilder (const 0)
455+zeros :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
456+zeros = matrixBuilder' (const 0)
461457
462458-- Ones Matrix
463459
464460-- | The ones matrix. A matrix wholly filled with ones.
465461--
466462-- Also known as T (Top) matrix.
467−ones :: (Num e, FromLists e cols rows, KnownNat (Count cols), KnownNat (Count rows)) => Matrix e cols rows
468−ones = matrixBuilder (const 1)
463+ones :: (Num e, FL cols rows, CountableDims cols rows) => Matrix e cols rows
464+ones = matrixBuilder' (const 1)
469465
470466-- Const Matrix
471467
472468-- | The constant matrix constructor. A matrix wholly filled with a given
473469-- value.
474−constant :: (Num e, FromLists e cols rows, KnownNat (Count cols), KnownNat (Count rows)) => e -> Matrix e cols rows
475−constant e = matrixBuilder (const e)
470+constant :: (Num e, FL cols rows, CountableDims cols rows) => e -> Matrix e cols rows
471+constant e = matrixBuilder' (const e)
476472
477473-- Bang Matrix
478474
479475-- | The T (Top) row vector matrix.
480−bang :: forall e cols. (Num e, Enum e, FromLists e cols (), KnownNat (Count cols)) => Matrix e cols ()
476+bang :: forall e cols. (Num e, Enum e, FL cols (), Countable cols) => Matrix e cols ()
481477bang =
482478 let c = fromInteger $ natVal (Proxy :: Proxy (Count cols))
483479 in fromLists [take c [1, 1 ..]]
484480
485−-- Identity Matrix
481+-- iden Matrix
486482
487−-- | Identity matrix.
488−identity :: (Num e, FromLists e cols cols, KnownNat (Count cols)) => Matrix e cols cols
489−identity = matrixBuilder (bool 0 1 . uncurry (==))
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 #-}
490487
491488-- Matrix composition (MMM)
492489
@@ -495,60 +492,90 @@ identity = matrixBuilder (bool 0 1 . uncurry (==))
495492-- This definition takes advantage of divide-and-conquer and fusion laws
496493-- from LAoP.
497494comp :: (Num e) => Matrix e cr rows -> Matrix e cols cr -> Matrix e cols rows
498−comp Empty Empty = Empty
499−comp (One a) (One b) = One (a * b)
500−comp (Junc a b) (Split c d) = comp a c + comp b d -- Divide-and-conquer law
501−comp (Split a b) c = Split (comp a c) (comp b c) -- Split fusion law
502−comp c (Junc a b) = Junc (comp c a) (comp c b) -- Junc fusion law
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)
503522
504523-- Projections
505524
506525-- | Biproduct first component projection
507−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
508−p1 =
509− let iden = identity :: Matrix e m m
510− zero = zeros :: Matrix e n m
511− in junc iden zero
526+p1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e (Either m n) m
527+p1 = join id zeros
512528
513529-- | Biproduct second component projection
514−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
515−p2 =
516− let iden = identity :: Matrix e n n
517− zero = zeros :: Matrix e m n
518− in junc zero iden
530+p2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e (Either m n) n
531+p2 = join zeros id
519532
520533-- Injections
521534
522535-- | Biproduct first component injection
523−i1 :: (Num e, KnownNat (Count n), KnownNat (Count m), FromLists e n m, FromLists e m m) => Matrix e m (Either m n)
536+i1 :: (Num e, CountableDims n m, FL n m, FL m m) => Matrix e m (Either m n)
524537i1 = tr p1
525538
526539-- | Biproduct second component injection
527−i2 :: (Num e, KnownNat (Count n), KnownNat (Count m), FromLists e m n, FromLists e n n) => Matrix e n (Either m n)
540+i2 :: (Num e, CountableDims n m, FL m n, FL n n) => Matrix e n (Either m n)
528541i2 = tr p2
529542
530543-- Dimensions
531544
532545-- | Obtain the number of rows.
533546--
534−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
535−-- dimensions in constant time.
536−--
537−-- TODO: A 'rows' function that does not need the 'KnownNat' constraint in
538−-- exchange for performance.
539−rows :: forall e cols rows. (KnownNat (Count rows)) => Matrix e cols rows -> Int
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
540551rows _ = fromInteger $ natVal (Proxy :: Proxy (Count rows))
541552
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+
542562-- | Obtain the number of columns.
543−--
544−-- NOTE: The 'KnownNat' constaint is needed in order to obtain the
545−-- dimensions in constant time.
546563--
547−-- TODO: A 'columns' function that does not need the 'KnownNat' constraint in
548−-- exchange for performance.
549−columns :: forall e cols rows. (KnownNat (Count cols)) => Matrix e cols rows -> Int
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
550568columns _ = fromInteger $ natVal (Proxy :: Proxy (Count cols))
551569
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+
552579-- Coproduct Bifunctor
553580
554581infixl 5 -|-
@@ -557,157 +584,172 @@ infixl 5 -|-
557584(-|-) ::
558585 forall e n k m j.
559586 ( Num e,
560− KnownNat (Count j),
561− KnownNat (Count k),
562− FromLists e k k,
563− FromLists e j k,
564− FromLists e k j,
565− FromLists e j j
587+ CountableDims j k,
588+ FL k k,
589+ FL j k,
590+ FL k j,
591+ FL j j
566592 ) =>
567593 Matrix e n k ->
568594 Matrix e m j ->
569595 Matrix e (Either n m) (Either k j)
570−(-|-) a b = Junc (i1 . a) (i2 . b)
596+(-|-) a b = Join (i1 . a) (i2 . b)
571597
572598-- Khatri Rao Product and projections
573599
574600-- | Khatri Rao product first component projection matrix.
575−kp1 ::
601+fstM ::
576602 forall e m k .
577603 ( Num e,
578− KnownNat (Count k),
579− FromLists e (FromNat (Count m * Count k)) m,
580− KnownNat (Count m),
581− KnownNat (Count (Normalize (m, k)))
604+ CountableDims k m,
605+ FL (Normalize (m, k)) m,
606+ CountableN (m, k)
582607 ) => Matrix e (Normalize (m, k)) m
583−kp1 = matrixBuilder f
608+fstM = matrixBuilder' f
584609 where
585610 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
586611 f (x, y)
587612 | y >= (x * offset) && y <= (x * offset + offset - 1) = 1
588− | otherwise = 0
613+ | otherwise = 0
589614
590615-- | Khatri Rao product second component projection matrix.
591−kp2 ::
616+sndM ::
592617 forall e m k .
593618 ( Num e,
594− KnownNat (Count k),
595− FromLists e (FromNat (Count m * Count k)) k,
596− KnownNat (Count m),
597− KnownNat (Count (Normalize (m, k)))
619+ CountableDims k m,
620+ FL (Normalize (m, k)) k,
621+ CountableN (m, k)
598622 ) => Matrix e (Normalize (m, k)) k
599−kp2 = matrixBuilder f
623+sndM = matrixBuilder' f
600624 where
601625 offset = fromInteger (natVal (Proxy :: Proxy (Count k)))
602626 f (x, y)
603627 | x == y || mod (y - x) offset == 0 = 1
604− | otherwise = 0
628+ | otherwise = 0
605629
606630-- | Khatri Rao Matrix product also known as matrix pairing.
607631--
608632-- NOTE: That this is not a true categorical product, see for instance:
609−--
633+--
610634-- @
611−-- | kp1 . khatri a b == a
612−-- khatri a b ==> |
613−-- | kp2 . khatri a b == b
635+-- | fstM . kr a b == a
636+-- kr a b ==> |
637+-- | sndM . kr a b == b
614638-- @
615639--
616640-- __Emphasis__ on the implication symbol.
617−khatri ::
618− forall e cols a b.
641+kr ::
642+ forall e cols a b.
619643 ( Num e,
620− KnownNat (Count a),
621− KnownNat (Count b),
622− KnownNat (Count (Normalize (a, b))),
623− FromLists e (Normalize (a, b)) a,
624− FromLists e (Normalize (a, b)) b
644+ CountableDims a b,
645+ CountableN (a, b),
646+ FL (Normalize (a, b)) a,
647+ FL (Normalize (a, b)) b
625648 ) => Matrix e cols a -> Matrix e cols b -> Matrix e cols (Normalize (a, b))
626−khatri a b =
627− let kp1' = kp1 @e @a @b
628− kp2' = kp2 @e @a @b
629− in (tr kp1') . a * (tr kp2') . 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)
630653
631654-- Product Bifunctor (Kronecker)
632655
633656infixl 4 ><
634657
635658-- | Matrix product functor also known as kronecker product
636−(><) ::
637− forall e m p n q.
659+(><) ::
660+ forall e m p n q.
638661 ( Num e,
639− KnownNat (Count m),
640− KnownNat (Count n),
641− KnownNat (Count p),
642− KnownNat (Count q),
643− KnownNat (Count (Normalize (m, n))),
644− FromLists e (Normalize (m, n)) m,
645− FromLists e (Normalize (m, n)) n,
646− KnownNat (Count (Normalize (p, q))),
647− FromLists e (Normalize (p, q)) p,
648− FromLists e (Normalize (p, q)) q
649− )
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+ )
650670 => Matrix e m p -> Matrix e n q -> Matrix e (Normalize (m, n)) (Normalize (p, q))
651671(><) a b =
652− let kp1' = kp1 @e @m @n
653− kp2' = kp2 @e @m @n
654− in khatri (a . kp1') (b . kp2')
672+ let fstM' = fstM @e @m @n
673+ sndM' = sndM @e @m @n
674+ in kr (a . fstM') (b . sndM')
655675
656−-- Matrix abide Junc Split
676+-- Matrix abide Join Fork
657677
658−-- | Matrix "abiding" followin the 'Junc'-'Split' abide law.
659−--
678+-- | Matrix "abiding" following the 'Join'-'Fork' exchange law.
679+--
660680-- Law:
661681--
662682-- @
663−-- 'Junc' ('Split' a c) ('Split' b d) == 'Split' ('Junc' a b) ('Junc' c d)
683+-- 'Join' ('Fork' a c) ('Fork' b d) == 'Fork' ('Join' a b) ('Join' c d)
664684-- @
665−abideJS :: Matrix e cols rows -> Matrix e cols rows
666−abideJS (Junc (Split a c) (Split b d)) = Split (Junc (abideJS a) (abideJS b)) (Junc (abideJS c) (abideJS d)) -- Junc-Split abide law
667−abideJS Empty = Empty
668−abideJS (One e) = One e
669−abideJS (Junc a b) = Junc (abideJS a) (abideJS b)
670−abideJS (Split a b) = Split (abideJS a) (abideJS b)
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)
671690
672−-- Matrix abide Split Junc
691+-- Matrix abide Fork Join
673692
674−-- | Matrix "abiding" followin the 'Split'-'Junc' abide law.
675−--
693+-- | Matrix "abiding" followin the 'Fork'-'Join' abide law.
694+--
676695-- @
677−-- 'Split' ('Junc' a b) ('Junc' c d) == 'Junc' ('Split' a c) ('Split' b d)
696+-- 'Fork' ('Join' a b) ('Join' c d) == 'Join' ('Fork' a c) ('Fork' b d)
678697-- @
679−abideSJ :: Matrix e cols rows -> Matrix e cols rows
680−abideSJ (Split (Junc a b) (Junc c d)) = Junc (Split (abideSJ a) (abideSJ c)) (Split (abideSJ b) (abideSJ d)) -- Split-Junc abide law
681−abideSJ Empty = Empty
682−abideSJ (One e) = One e
683−abideSJ (Junc a b) = Junc (abideSJ a) (abideSJ b)
684−abideSJ (Split a b) = Split (abideSJ a) (abideSJ b)
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)
685703
686704-- Matrix transposition
687705
688706-- | Matrix transposition.
689707tr :: Matrix e cols rows -> Matrix e rows cols
690−tr Empty = Empty
691−tr (One e) = One e
692−tr (Junc a b) = Split (tr a) (tr b)
693−tr (Split a b) = Junc (tr a) (tr b)
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)
694711
695712-- Selective 'select' operator
696713
697714-- | Selective functors 'select' operator equivalent inspired by the
698715-- ArrowMonad solution presented in the paper.
699−select :: (Num e, FromLists e b b, KnownNat (Count b)) => Matrix e cols (Either a b) -> Matrix e a b -> Matrix e cols b
700−select m y = junc y identity . m
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
701743
702744-- McCarthy's Conditional
703745
704746-- | McCarthy's Conditional expresses probabilistic choice.
705747cond ::
706− ( cols ~ FromNat (Count cols),
707− KnownNat (Count cols),
708− FromLists e () cols,
709− FromLists e cols (),
710− FromLists e cols cols,
748+ ( Trivial cols,
749+ Countable cols,
750+ FL () cols,
751+ FL cols (),
752+ FL cols cols,
711753 Bounded a,
712754 Enum a,
713755 Num e,
@@ -715,14 +757,14 @@ cond ::
715757 )
716758 =>
717759 (a -> Bool) -> Matrix e cols rows -> Matrix e cols rows -> Matrix e cols rows
718−cond p f g = junc f g . grd p
719−
720−grd ::
721− ( q ~ FromNat (Count q),
722− KnownNat (Count q),
723− FromLists e () q,
724− FromLists e q (),
725− FromLists e q q,
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,
726768 Bounded a,
727769 Enum a,
728770 Num e,
@@ -730,62 +772,88 @@ grd ::
730772 )
731773 =>
732774 (a -> Bool) -> Matrix e q (Either q q)
733−grd f = split (corr f) (corr (not . f))
734−
735−corr ::
736− forall e a q .
737− ( q ~ FromNat (Count q),
738− KnownNat (Count q),
739− FromLists e () q,
740− FromLists e q (),
741− FromLists e q q,
742− Bounded a,
743− Enum a,
744− Num e,
745− Ord e
746− )
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+ )
747786 => (a -> Bool) -> Matrix e q q
748−corr p = let f = fromF p :: Matrix e q ()
749− in khatri f (identity :: Matrix e q q)
787+corr p = let f = fromF' p :: Matrix e q ()
788+ in kr f (id :: Matrix e q q)
750789
751790-- Pretty print
752791
753792prettyAux :: Show e => [[e]] -> [[e]] -> String
754793prettyAux [] _ = ""
755−prettyAux [[e]] m = "│ " ++ fill (show e) ++ " │\n"
794+prettyAux [[e]] m = "│ " ++ fill (show e) ++ " │\n"
756795 where
757796 v = fmap show m
758797 widest = maximum $ fmap length v
759798 fill str = replicate (widest - length str - 2) ' ' ++ str
760−prettyAux [h] m = "│ " ++ fill (unwords $ map show h) ++ " │\n"
799+prettyAux [h] m = "│ " ++ fill (unwords $ map show h) ++ " │\n"
761800 where
762− v = fmap show m
763− widest = maximum $ fmap length v
801+ v = fmap show m
802+ widest = maximum $ fmap length v
764803 fill str = replicate (widest - length str - 2) ' ' ++ str
765−prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
804+prettyAux (h : t) l = "│ " ++ fill (unwords $ map show h) ++ " │\n" ++
766805 prettyAux t l
767806 where
768− v = fmap show l
769− widest = maximum $ fmap length v
807+ v = fmap show l
808+ widest = maximum $ fmap length v
770809 fill str = replicate (widest - length str - 2) ' ' ++ str
771810
772811-- | Matrix pretty printer
773−pretty :: (KnownNat (Count cols), Show e) => Matrix e cols rows -> String
774−pretty m = "┌ " ++ unwords (replicate (columns m) blank) ++ " ┐\n" ++
775− prettyAux (toLists m) (toLists m) ++
776− "└ " ++ unwords (replicate (columns m) blank) ++ " ┘"
777− where
778− v = fmap show (toList m)
779− widest = maximum $ fmap length v
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
780822 fill str = replicate (widest - length str) ' ' ++ str
781− blank = fill ""
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)
782839
783840-- | Matrix pretty printer
784−prettyPrint :: (KnownNat (Count cols), Show e) => Matrix e cols rows -> IO ()
841+prettyPrint :: (CountableDims cols rows, Show e) => Matrix e cols rows -> IO ()
785842prettyPrint = putStrLn . pretty
786843
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+
787852-- Relational operators functions
788853
854+type Boolean = Natural 0 1
855+type Relation a b = Matrix Boolean a b
856+
789857-- | Helper conversion function
790858toBool :: (Num e, Eq e) => e -> Bool
791859toBool n
@@ -797,136 +865,110 @@ fromBool :: Bool -> Natural 0 1
797865fromBool True = nat 1
798866fromBool False = nat 0
799867
868+-- | 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)
873+
800874-- | Relational addition
801−orM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
802−orM Empty Empty = Empty
803−orM (One a) (One b) = One (fromBool (toBool a || toBool b))
804−orM (Junc a b) (Junc c d) = Junc (orM a c) (orM b d)
805−orM (Split a b) (Split c d) = Split (orM a c) (orM b d)
806−orM x@(Split _ _) y@(Junc _ _) = orM x (abideJS y)
807−orM x@(Junc _ _) y@(Split _ _) = orM (abideJS x) y
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
808881
809882-- | Relational multiplication
810−andM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
811−andM Empty Empty = Empty
812−andM (One a) (One b) = One (fromBool (toBool a && toBool b))
813−andM (Junc a b) (Junc c d) = Junc (andM a c) (andM b d)
814−andM (Split a b) (Split c d) = Split (andM a c) (andM b d)
815−andM x@(Split _ _) y@(Junc _ _) = andM x (abideJS y)
816−andM x@(Junc _ _) y@(Split _ _) = andM (abideJS x) y
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
817889
818890-- | Relational subtraction
819−subM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
820−subM Empty Empty = Empty
821−subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
822−subM (Junc a b) (Junc c d) = Junc (subM a c) (subM b d)
823−subM (Split a b) (Split c d) = Split (subM a c) (subM b d)
824−subM x@(Split _ _) y@(Junc _ _) = subM x (abideJS y)
825−subM x@(Junc _ _) y@(Split _ _) = subM (abideJS x) y
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
826897
827898-- | Matrix relational composition.
828−compRel :: Matrix (Natural 0 1) cr rows -> Matrix (Natural 0 1) cols cr -> Matrix (Natural 0 1) cols rows
829−compRel Empty Empty = Empty
830−compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
831−compRel (Junc a b) (Split c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
832−compRel (Split a b) c = Split (compRel a c) (compRel b c) -- Split fusion law
833−compRel c (Junc a b) = Junc (compRel c a) (compRel c b) -- Junc fusion law
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
834921
835922-- | Lifts functions to relations with arbitrary dimensions.
836923--
837924-- NOTE: Be careful to not ask for a relation bigger than the cardinality of
838925-- types @a@ or @b@ allows.
839−fromFRel ::
926+fromFRel' ::
840927 forall a b cols rows.
841− ( Bounded a,
842− Bounded b,
843− Enum a,
844− Enum b,
845− Eq b,
846− KnownNat (Count cols),
847− KnownNat (Count rows),
848− FromLists (Natural 0 1) rows cols
928+ ( Liftable Boolean a b,
929+ CountableDims cols rows,
930+ FL rows cols
849931 ) =>
850932 (a -> b) ->
851− Matrix (Natural 0 1) cols rows
852−fromFRel f =
853− let minA = minBound @a
854− maxA = maxBound @a
855− minB = minBound @b
856− maxB = maxBound @b
857− ccols = fromInteger $ natVal (Proxy :: Proxy (Count cols))
858− rrows = fromInteger $ natVal (Proxy :: Proxy (Count rows))
859− elementsA = take ccols [minA .. maxA]
860− elementsB = take rrows [minB .. maxB]
861− combinations = (,) <$> elementsA <*> elementsB
862− combAp = map snd . sort . map (\(a, b) -> if f a == b
863− then ((fromEnum a, fromEnum b), nat 1)
864− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
865− mList = buildList combAp rrows
866− in tr $ fromLists mList
867− where
868− buildList [] _ = []
869− buildList l r = take r l : buildList (drop r l) r
933+ Relation cols rows
934+fromFRel' = fromF'
870935
871936-- | Lifts functions to relations with dimensions matching @a@ and @b@
872937-- cardinality's.
873−fromFRel' ::
938+fromFRel ::
874939 forall a b.
875− ( Bounded a,
876− Bounded b,
877− Enum a,
878− Enum b,
879− Eq b,
880− KnownNat (Count (Normalize a)),
881− KnownNat (Count (Normalize b)),
882− FromLists (Natural 0 1) (Normalize b) (Normalize a)
940+ ( Liftable Boolean a b,
941+ CountableDimsN a b,
942+ FLN b a
883943 ) =>
884944 (a -> b) ->
885− Matrix (Natural 0 1) (Normalize a) (Normalize b)
886−fromFRel' f =
887− let minA = minBound @a
888− maxA = maxBound @a
889− minB = minBound @b
890− maxB = maxBound @b
891− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
892− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
893− elementsA = take ccols [minA .. maxA]
894− elementsB = take rrows [minB .. maxB]
895− combinations = (,) <$> elementsA <*> elementsB
896− combAp = map snd . sort . map (\(a, b) -> if f a == b
897− then ((fromEnum a, fromEnum b), nat 1)
898− else ((fromEnum a, fromEnum b), nat 0)) $ combinations
899− mList = buildList combAp rrows
900− in tr $ fromLists mList
901− where
902− buildList [] _ = []
903− buildList l r = take r l : buildList (drop r l) r
945+ Relation (Normalize a) (Normalize b)
946+fromFRel = fromFRel'
904947
905948-- | Lifts a relation function to a Boolean Matrix
906−toRel ::
949+toRel ::
907950 forall a b.
908951 ( Bounded a,
909952 Bounded b,
910953 Enum a,
911954 Enum b,
912955 Eq b,
913− KnownNat (Count (Normalize a)),
914− KnownNat (Count (Normalize b)),
915− FromLists (Natural 0 1) (Normalize b) (Normalize a)
916− )
917− => (a -> b -> Bool) -> Matrix (Natural 0 1) (Normalize a) (Normalize b)
956+ CountableDims a b,
957+ FLN b a
958+ )
959+ => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
918960toRel f =
919961 let minA = minBound @a
920962 maxA = maxBound @a
921963 minB = minBound @b
922964 maxB = maxBound @b
923− ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
924− rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
965+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count a))
966+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count b))
925967 elementsA = take ccols [minA .. maxA]
926968 elementsB = take rrows [minB .. maxB]
927969 combinations = (,) <$> elementsA <*> elementsB
928− combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
929− then ((fromEnum a, fromEnum b), nat 1)
970+ combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
971+ then ((fromEnum a, fromEnum b), nat 1)
930972 else ((fromEnum a, fromEnum b), nat 0)) $ combinations
931973 mList = buildList combAp rrows
932974 in tr $ fromLists mList