on master help sign in
Merge pull request #1 from bolt12/relation

Relation Module

commit95920192e1a950c530ac3e22b85b981ae91b20af authorArmando Santos <armandoifsantos@gmail.com> dateWed 29 Jan 2020, 00:47 (7 years ago) parent9d9ba172fec7d9
16 files changed+1574−213
.ghc.environment.x86_64-linux-8.6.5+17 README.md+82−5 app/Main.hs+72−3 hackage.sh+10 laop-0.1.0.0-docs.tar.gz package.yaml+10−10 src/Dist.hs → src/LAoP/Dist.hs+3−3 src/Dist/Internal.hs → src/LAoP/Dist/Internal.hs+3−3 src/Matrix/Internal.hs → src/LAoP/Matrix/Internal.hs+86−19 src/Matrix/Nat.hs → src/LAoP/Matrix/Nat.hs+3−3 src/Matrix/Type.hs → src/LAoP/Matrix/Type.hs+20−3 src/LAoP/Relation.hs+156 src/LAoP/Relation/Internal.hs+1042 src/Utils.hs → src/LAoP/Utils.hs+6−3 src/Utils/Internal.hs → src/LAoP/Utils/Internal.hs+64−2 src/Relation/Internal.hs−159
.ghc.environment.x86_64-linux-8.6.5new file+17
@@ -0,0 +1,17 @@
1+-- This is a GHC environment file written by cabal. This means you can
2+-- run ghc or ghci and get the environment of the project as a whole.
3+-- But you still need to use cabal repl $target to get the environment
4+-- of specific components (libs, exes, tests etc) because each one can
5+-- have its own source dirs, cpp flags etc.
6+--
7+clear-package-db
8+global-package-db
9+package-db /home/bolt/.cabal/store/ghc-8.6.5/package.db
10+package-db packagedb/ghc-8.6.5
11+package-id laop-0.1.0.0-inplace
12+package-id base-4.12.0.0
13+package-id ghc-prim-0.5.3
14+package-id rts
15+package-id integer-gmp-1.0.2.0
16+package-id deepseq-1.4.4.0
17+package-id array-0.5.3.0
README.md+82−5
@@ -16,15 +16,20 @@ See the candidate package in hackage [here](https://hackage.haskell.org/package/
1616
1717This library offers:
1818
19−- One that uses normal datatypes (`Void`, `()`, `Either`) for matrix dimensions and two
19+- An internal module representation that uses normal datatypes (`Void`, `()`, `Either`) for matrix dimensions and two
2020 type families `FromNat` and `Count` to make it easier to work with these type of matrices.
21−- Other that uses type level naturals for the dimensions and is just a newtype wrapper
22− around the other matrix data type.
21+- An interfacing module that uses generalised types for the dimensions and is just a newtype wrapper
22+ around the internal matrix data type.
23+- An interfacing module that uses type level naturals for the dimensions and is just a newtype wrapper
24+ around the internal matrix data type.
25+- An interfacing module that restricts the matrix contents to being only 0's or 1's (True
26+ and False). This module is called 'Relation' and offers many of the combinators seen in
27+ AoP and Relational Calculus/Algebra.
2328- A very simple Probabilistic Programming module and several functions and data types to
2429 make it easier to deal with sample space.
2530
2631Given this, this new matrix formulation compared to other libraries one has much more advantages, such as:
27−
32+
2833- Has an inductive definition enabling writing matrix manipulation functions in a much more elegant and calculational way;
2934- Statically typed dimensions;
3035- Polymorphic data type dimensions;
@@ -33,7 +38,7 @@ Given this, this new matrix formulation compared to other libraries one has much
3338- Fast type natural conversion via `FromNat` type family;
3439- Matrix `Junc` and `Split`-ing in O(1);
3540- Matrix composition takes advantage of divide-and-conquer and fusion laws.
36−
41+
3742Unfortunately, this approach does not solve the issue of type dimensions being in some way constrainted making it impossible to write Arrow instances, for example. Type inference isn't perfect, when it comes to infer the types of matrices which dimensions are computed using type level naturals multiplication, the compiler needs type annotations in order to succeed.
3843
3944## Notes
@@ -116,6 +121,73 @@ grass_wet = row [0,1] . kp1
116121rainning :: Matrix Double (Bool, (Bool, Bool)) One
117122rainning = row [0,1] . kp2 . kp2
118123
124+-- Alcuin Puzzle
125+
126+data Being = Farmer | Fox | Goose | Beans
127+ deriving (Bounded, Enum, Eq, Show, Generic)
128+
129+data Bank = LeftB | RightB
130+ deriving (Bounded, Enum, Eq, Show, Generic)
131+
132+eats :: Being -> Being -> Bool
133+eats Fox Goose = True
134+eats Goose Beans = True
135+eats _ _ = False
136+
137+eatsR :: R.Relation Being Being
138+eatsR = R.toRel eats
139+
140+cross :: Bank -> Bank
141+cross LeftB = RightB
142+cross RightB = LeftB
143+
144+crossR :: R.Relation Bank Bank
145+crossR = R.fromF' cross
146+
147+-- | Initial state, everyone in the left bank
148+locationLeft :: Being -> Bank
149+locationLeft _ = LeftB
150+
151+locationLeftR :: R.Relation Being Bank
152+locationLeftR = R.fromF' locationLeft
153+
154+-- | Initial state, everyone in the right bank
155+locationRight :: Being -> Bank
156+locationRight _ = RightB
157+
158+locationRightR :: R.Relation Being Bank
159+locationRightR = R.fromF' locationRight
160+
161+-- Properties
162+
163+-- Being at the same bank
164+sameBank :: R.Relation Being Bank -> R.Relation Being Being
165+sameBank = R.ker
166+
167+-- Risk of somebody eating somebody else
168+canEat :: R.Relation Being Bank -> R.Relation Being Being
169+canEat w = sameBank w `R.intersection` eatsR
170+
171+-- "Starvation" property.
172+inv :: R.Relation Being Bank -> Bool
173+inv w = (w `R.comp` canEat w) `R.sse` (w `R.comp` farmer)
174+ where
175+ farmer :: R.Relation Being Being
176+ farmer = R.fromF' (const Farmer)
177+
178+-- Arbitrary state
179+bankState :: Being -> Bank -> Bool
180+bankState Farmer LeftB = True
181+bankState Fox LeftB = True
182+bankState Goose RightB = True
183+bankState Beans RightB = True
184+bankState _ _ = False
185+
186+bankStateR :: R.Relation Being Bank
187+bankStateR = R.toRel bankState
188+
189+-- Main
190+
119191main :: IO ()
120192main = do
121193 putStrLn "Monty Hall Problem solution:"
@@ -130,6 +202,8 @@ main = do
130202 prettyPrint (grass_wet . state)
131203 putStrLn "\n Probability of rain:"
132204 prettyPrint (rainning . state)
205+ putStrLn "\n Is the arbitrary state a valid state? (Alcuin Puzzle)"
206+ print (inv bankStateR)
133207```
134208
135209```Shell
@@ -188,4 +262,7 @@ Monty Hall Problem solution:
188262┌ ┐
189263│ 0.2 │
190264└ ┘
265+
266+Is the arbitrary state a valid state? (Alcuin Puzzle)
267+False
191268```
app/Main.hs+72−3
@@ -6,9 +6,10 @@
66
77module Main where
88
9−import Matrix.Type
10−import Utils
11−import Dist
9+import LAoP.Matrix.Type
10+import qualified LAoP.Relation as R
11+import LAoP.Utils
12+import LAoP.Dist
1213import GHC.TypeLits
1314import Data.Coerce
1415import GHC.Generics
@@ -71,6 +72,72 @@ grass_wet = row [0,1] . kp1
7172rainning :: Matrix Double (Bool, (Bool, Bool)) One
7273rainning = row [0,1] . kp2 . kp2
7374
75+-- Alcuin Puzzle
76+
77+data Being = Farmer | Fox | Goose | Beans
78+ deriving (Bounded, Enum, Eq, Show, Generic)
79+
80+data Bank = LeftB | RightB
81+ deriving (Bounded, Enum, Eq, Show, Generic)
82+
83+eats :: Being -> Being -> Bool
84+eats Fox Goose = True
85+eats Goose Beans = True
86+eats _ _ = False
87+
88+eatsR :: R.Relation Being Being
89+eatsR = R.toRel eats
90+
91+cross :: Bank -> Bank
92+cross LeftB = RightB
93+cross RightB = LeftB
94+
95+crossR :: R.Relation Bank Bank
96+crossR = R.fromF' cross
97+
98+-- | Initial state, everyone in the left bank
99+locationLeft :: Being -> Bank
100+locationLeft _ = LeftB
101+
102+locationLeftR :: R.Relation Being Bank
103+locationLeftR = R.fromF' locationLeft
104+
105+-- | Initial state, everyone in the right bank
106+locationRight :: Being -> Bank
107+locationRight _ = RightB
108+
109+locationRightR :: R.Relation Being Bank
110+locationRightR = R.fromF' locationRight
111+
112+-- Properties
113+
114+-- Being at the same bank
115+sameBank :: R.Relation Being Bank -> R.Relation Being Being
116+sameBank = R.ker
117+
118+-- Risk of somebody eating somebody else
119+canEat :: R.Relation Being Bank -> R.Relation Being Being
120+canEat w = sameBank w `R.intersection` eatsR
121+
122+-- "Starvation" property.
123+inv :: R.Relation Being Bank -> Bool
124+inv w = (w `R.comp` canEat w) `R.sse` (w `R.comp` farmer)
125+ where
126+ farmer :: R.Relation Being Being
127+ farmer = R.fromF' (const Farmer)
128+
129+-- Arbitrary state
130+bankState :: Being -> Bank -> Bool
131+bankState Farmer LeftB = True
132+bankState Fox LeftB = True
133+bankState Goose RightB = True
134+bankState Beans RightB = True
135+bankState _ _ = False
136+
137+bankStateR :: R.Relation Being Bank
138+bankStateR = R.toRel bankState
139+
140+-- Main
74141main :: IO ()
75142main = do
76143 putStrLn "Monty Hall Problem solution:"
@@ -85,3 +152,5 @@ main = do
85152 prettyPrint (grass_wet . state)
86153 putStrLn "\n Probability of rain:"
87154 prettyPrint (rainning . state)
155+ putStrLn "\n Is the arbitrary state a valid state? (Alcuin Puzzle)"
156+ print (inv bankStateR)
hackage.shnew file+10
@@ -0,0 +1,10 @@
1+#!/bin/sh
2+set -e
3+
4+dir=$(mktemp -d dist-docs.XXXXXX)
5+trap 'rm -r "$dir"' EXIT
6+
7+# assumes cabal 2.4 or later
8+cabal v2-haddock --builddir="$dir" --haddock-for-hackage --enable-doc
9+
10+cabal upload -d $dir/*-docs.tar.gz
laop-0.1.0.0-docs.tar.gznew file

Binary file not shown.

package.yaml+10−10
@@ -25,16 +25,16 @@ dependencies:
2525library:
2626 source-dirs: src
2727
28−executables:
29− laop-exe:
30− main: Main.hs
31− source-dirs: app
32− ghc-options:
33− - -threaded
34− - -rtsopts
35− - -with-rtsopts=-N
36− dependencies:
37− - laop
28+#executables:
29+# laop-exe:
30+# main: Main.hs
31+# source-dirs: app
32+# ghc-options:
33+# - -threaded
34+# - -rtsopts
35+# - -with-rtsopts=-N
36+# dependencies:
37+# - laop
3838
3939tests:
4040 laop-test:
src/Dist.hs → src/LAoP/Dist.hsrenamed+3−3
@@ -1,6 +1,6 @@
11-----------------------------------------------------------------------------
22-- |
3−-- Module : Dist
3+-- Module : LAoP.Dist
44-- Copyright : (c) Armando Santos 2019-2020
55-- Maintainer : armandoifsantos@gmail.com
66-- Stability : experimental
@@ -16,7 +16,7 @@
1616--
1717-----------------------------------------------------------------------------
1818
19−module Dist
19+module LAoP.Dist
2020 ( -- | If the sum of the rows of a column matrix
2121 -- is equal to 1 then this stochastic matrix
2222 -- can be seen as a probability distribution.
@@ -66,4 +66,4 @@ module Dist
6666 )
6767where
6868
69−import Dist.Internal
69+import LAoP.Dist.Internal
src/Dist/Internal.hs → src/LAoP/Dist/Internal.hsrenamed+3−3
@@ -7,7 +7,7 @@
77{-# LANGUAGE DataKinds #-}
88{-# LANGUAGE RankNTypes #-}
99
10−module Dist.Internal
10+module LAoP.Dist.Internal
1111 (
1212 Dist(..),
1313 Prob,
@@ -32,8 +32,8 @@ module Dist.Internal
3232 )
3333 where
3434
35−import Matrix.Type
36−import Utils
35+import LAoP.Matrix.Type
36+import LAoP.Utils
3737import GHC.TypeLits
3838import Data.Proxy
3939import Data.List (sortBy)
src/Matrix/Internal.hs → src/LAoP/Matrix/Internal.hsrenamed+86−19
@@ -1,3 +1,4 @@
1+{-# LANGUAGE TypeFamilyDependencies #-}
12{-# LANGUAGE AllowAmbiguousTypes #-}
23{-# LANGUAGE DataKinds #-}
34{-# LANGUAGE FlexibleContexts #-}
@@ -9,13 +10,12 @@
910{-# LANGUAGE ScopedTypeVariables #-}
1011{-# LANGUAGE StandaloneDeriving #-}
1112{-# LANGUAGE TypeApplications #-}
12−{-# LANGUAGE TypeFamilies #-}
1313{-# LANGUAGE TypeOperators #-}
1414{-# LANGUAGE UndecidableInstances #-}
1515
1616-----------------------------------------------------------------------------
1717-- |
18−-- Module : Matrix.Internal
18+-- Module : LAoP.Matrix.Internal
1919-- Copyright : (c) Armando Santos 2019-2020
2020-- Maintainer : armandoifsantos@gmail.com
2121-- Stability : experimental
@@ -34,7 +34,7 @@
3434--
3535-----------------------------------------------------------------------------
3636
37−module Matrix.Internal
37+module LAoP.Matrix.Internal
3838 ( -- | This definition makes use of the fact that 'Void' is
3939 -- isomorphic to 0 and '()' to 1 and captures matrix
4040 -- dimensions as stacks of 'Either's.
@@ -134,15 +134,20 @@ module Matrix.Internal
134134 toBool,
135135 fromBool,
136136 compRel,
137+ divR,
138+ divL,
139+ divS,
137140 fromFRel,
138141 fromFRel',
142+ toRel,
143+ negateM,
139144 orM,
140145 andM,
141146 subM
142147 )
143148 where
144149
145−import Utils
150+import LAoP.Utils.Internal
146151import Data.Bool
147152import Data.Kind
148153import Data.List
@@ -170,17 +175,18 @@ deriving instance (Show e) => Show (Matrix e cols rows)
170175-- 'Generic' instance.
171176type family Count (d :: Type) :: Nat where
172177 Count (Natural n m) = (m - n) + 1
173− Count (Either a b) = (+) (Count a) (Count b)
174− Count (a, b) = (*) (Count a) (Count b)
175− Count (a -> b) = (^) (Count b) (Count a)
178+ Count (Powerset a) = (^) (Count a) (Count a)
179+ Count (Either a b) = (+) (Count a) (Count b)
180+ Count (a, b) = (*) (Count a) (Count b)
181+ Count (a -> b) = (^) (Count b) (Count a)
176182 -- Generics
177− Count (M1 _ _ f p) = Count (f p)
178− Count (K1 _ _ _) = 1
179− Count (V1 _) = 0
180− Count (U1 _) = 1
183+ Count (M1 _ _ f p) = Count (f p)
184+ Count (K1 _ _ _) = 1
185+ Count (V1 _) = 0
186+ Count (U1 _) = 1
181187 Count ((:*:) a b p) = Count (a p) * Count (b p)
182188 Count ((:+:) a b p) = Count (a p) + Count (b p)
183− Count d = Count (Rep d R)
189+ Count d = Count (Rep d R)
184190
185191-- | Type family that computes of a given type dimension from a given natural
186192--
@@ -785,6 +791,9 @@ prettyPrint = putStrLn . pretty
785791
786792-- Relational operators functions
787793
794+type Boolean = Natural 0 1
795+type Relation a b = Matrix Boolean a b
796+
788797-- | Helper conversion function
789798toBool :: (Num e, Eq e) => e -> Bool
790799toBool n
@@ -796,8 +805,16 @@ fromBool :: Bool -> Natural 0 1
796805fromBool True = nat 1
797806fromBool False = nat 0
798807
808+-- | Relational negation
809+negateM :: Relation cols rows -> Relation cols rows
810+negateM Empty = Empty
811+negateM (One (Nat 0)) = One (Nat 1)
812+negateM (One (Nat 1)) = One (Nat 0)
813+negateM (Junc a b) = Junc (negateM a) (negateM b)
814+negateM (Split a b) = Split (negateM a) (negateM b)
815+
799816-- | Relational addition
800−orM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
817+orM :: Relation cols rows -> Relation cols rows -> Relation cols rows
801818orM Empty Empty = Empty
802819orM (One a) (One b) = One (fromBool (toBool a || toBool b))
803820orM (Junc a b) (Junc c d) = Junc (orM a c) (orM b d)
@@ -806,7 +823,7 @@ orM x@(Split _ _) y@(Junc _ _) = orM x (abideJS y)
806823orM x@(Junc _ _) y@(Split _ _) = orM (abideJS x) y
807824
808825-- | Relational multiplication
809−andM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
826+andM :: Relation cols rows -> Relation cols rows -> Relation cols rows
810827andM Empty Empty = Empty
811828andM (One a) (One b) = One (fromBool (toBool a && toBool b))
812829andM (Junc a b) (Junc c d) = Junc (andM a c) (andM b d)
@@ -815,7 +832,7 @@ andM x@(Split _ _) y@(Junc _ _) = andM x (abideJS y)
815832andM x@(Junc _ _) y@(Split _ _) = andM (abideJS x) y
816833
817834-- | Relational subtraction
818−subM :: Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows -> Matrix (Natural 0 1) cols rows
835+subM :: Relation cols rows -> Relation cols rows -> Relation cols rows
819836subM Empty Empty = Empty
820837subM (One a) (One b) = if a - b < nat 0 then One (nat 0) else One (a - b)
821838subM (Junc a b) (Junc c d) = Junc (subM a c) (subM b d)
@@ -824,13 +841,31 @@ subM x@(Split _ _) y@(Junc _ _) = subM x (abideJS y)
824841subM x@(Junc _ _) y@(Split _ _) = subM (abideJS x) y
825842
826843-- | Matrix relational composition.
827−compRel :: Matrix (Natural 0 1) cr rows -> Matrix (Natural 0 1) cols cr -> Matrix (Natural 0 1) cols rows
844+compRel :: Relation cr rows -> Relation cols cr -> Relation cols rows
828845compRel Empty Empty = Empty
829846compRel (One a) (One b) = One (fromBool (toBool a && toBool b))
830−compRel (Junc a b) (Split c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
847+compRel (Junc a b) (Split c d) = orM (compRel a c) (compRel b d) -- Divide-and-conquer law
831848compRel (Split a b) c = Split (compRel a c) (compRel b c) -- Split fusion law
832849compRel c (Junc a b) = Junc (compRel c a) (compRel c b) -- Junc fusion law
833850
851+-- | Matrix relational right division
852+divR :: Relation b c -> Relation b a -> Relation a c
853+divR Empty Empty = Empty
854+divR (One a) (One b) = One (fromBool (not (toBool b) || toBool a)) -- b implies a
855+divR (Junc a b) (Junc c d) = andM (divR a c) (divR b d)
856+divR (Split a b) c = Split (divR a c) (divR b c)
857+divR c (Split a b) = Junc (divR c a) (divR c b)
858+
859+-- | Matrix relational left division
860+divL :: Relation c b -> Relation a b -> Relation a c
861+divL x y = tr (divR (tr y) (tr x))
862+
863+-- | Matrix relational symmetric division
864+divS :: Relation c a -> Relation b a -> Relation c b
865+divS s r = divL r s `intersection` divR (tr r) (tr s)
866+ where
867+ intersection = andM
868+
834869-- | Lifts functions to relations with arbitrary dimensions.
835870--
836871-- NOTE: Be careful to not ask for a relation bigger than the cardinality of
@@ -847,7 +882,7 @@ fromFRel ::
847882 FromLists (Natural 0 1) rows cols
848883 ) =>
849884 (a -> b) ->
850− Matrix (Natural 0 1) cols rows
885+ Relation cols rows
851886fromFRel f =
852887 let minA = minBound @a
853888 maxA = maxBound @a
@@ -881,7 +916,7 @@ fromFRel' ::
881916 FromLists (Natural 0 1) (Normalize b) (Normalize a)
882917 ) =>
883918 (a -> b) ->
884− Matrix (Natural 0 1) (Normalize a) (Normalize b)
919+ Relation (Normalize a) (Normalize b)
885920fromFRel' f =
886921 let minA = minBound @a
887922 maxA = maxBound @a
@@ -900,3 +935,35 @@ fromFRel' f =
900935 where
901936 buildList [] _ = []
902937 buildList l r = take r l : buildList (drop r l) r
938+
939+-- | Lifts a relation function to a Boolean Matrix
940+toRel ::
941+ forall a b.
942+ ( Bounded a,
943+ Bounded b,
944+ Enum a,
945+ Enum b,
946+ Eq b,
947+ KnownNat (Count (Normalize a)),
948+ KnownNat (Count (Normalize b)),
949+ FromLists (Natural 0 1) (Normalize b) (Normalize a)
950+ )
951+ => (a -> b -> Bool) -> Relation (Normalize a) (Normalize b)
952+toRel f =
953+ let minA = minBound @a
954+ maxA = maxBound @a
955+ minB = minBound @b
956+ maxB = maxBound @b
957+ ccols = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize a)))
958+ rrows = fromInteger $ natVal (Proxy :: Proxy (Count (Normalize b)))
959+ elementsA = take ccols [minA .. maxA]
960+ elementsB = take rrows [minB .. maxB]
961+ combinations = (,) <$> elementsA <*> elementsB
962+ combAp = map snd . sort . map (\(a, b) -> if uncurry f (a, b)
963+ then ((fromEnum a, fromEnum b), nat 1)
964+ else ((fromEnum a, fromEnum b), nat 0)) $ combinations
965+ mList = buildList combAp rrows
966+ in tr $ fromLists mList
967+ where
968+ buildList [] _ = []
969+ buildList l r = take r l : buildList (drop r l) r
src/Matrix/Nat.hs → src/LAoP/Matrix/Nat.hsrenamed+3−3
@@ -15,7 +15,7 @@
1515
1616-----------------------------------------------------------------------------
1717-- |
18−-- Module : Matrix.Nat
18+-- Module : LAoP.Matrix.Nat
1919-- Copyright : (c) Armando Santos 2019-2020
2020-- Maintainer : armandoifsantos@gmail.com
2121-- Stability : experimental
@@ -33,7 +33,7 @@
3333--
3434-----------------------------------------------------------------------------
3535
36−module Matrix.Nat
36+module LAoP.Matrix.Nat
3737 ( -- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
3838 --
3939 -- LAoP generalises relations and functions treating them as
@@ -142,7 +142,7 @@ import Data.Proxy
142142import GHC.TypeLits
143143import Control.DeepSeq
144144import qualified Control.Category as C
145−import qualified Matrix.Internal as I
145+import qualified LAoP.Matrix.Internal as I
146146
147147newtype Matrix e (cols :: Nat) (rows :: Nat) = M (I.Matrix e (I.FromNat cols) (I.FromNat rows))
148148 deriving (Show, Num, Eq, Ord, NFData) via (I.Matrix e (I.FromNat cols) (I.FromNat rows))
src/Matrix/Type.hs → src/LAoP/Matrix/Type.hsrenamed+20−3
@@ -15,7 +15,7 @@
1515
1616-----------------------------------------------------------------------------
1717-- |
18−-- Module : Matrix.Type
18+-- Module : LAoP.Matrix.Type
1919-- Copyright : (c) Armando Santos 2019-2020
2020-- Maintainer : armandoifsantos@gmail.com
2121-- Stability : experimental
@@ -36,7 +36,7 @@
3636--
3737-----------------------------------------------------------------------------
3838
39−module Matrix.Type
39+module LAoP.Matrix.Type
4040 ( -- | LAoP (Linear Algebra of Programming) Inductive Matrix definition.
4141 --
4242 -- LAoP generalises relations and functions treating them as
@@ -149,6 +149,9 @@ module Matrix.Type
149149 fromF,
150150 fromF',
151151
152+ -- * Relation
153+ toRel,
154+
152155 -- * Matrix printing
153156 pretty,
154157 prettyPrint
@@ -160,8 +163,9 @@ import Data.Proxy
160163import Data.Kind
161164import GHC.TypeLits
162165import Control.DeepSeq
166+import LAoP.Utils
163167import qualified Control.Category as C
164−import qualified Matrix.Internal as I
168+import qualified LAoP.Matrix.Internal as I
165169
166170newtype Matrix e (cols :: Type) (rows :: Type) = M (I.Matrix e (I.Normalize cols) (I.Normalize rows))
167171 deriving (Show, Num, Eq, Ord, NFData) via (I.Matrix e (I.Normalize cols) (I.Normalize rows))
@@ -341,6 +345,19 @@ fromF' ::
341345 Matrix e a b
342346fromF' = M . I.fromF'
343347
348+-- | Lifts relation functions to Boolean Matrix
349+toRel ::
350+ ( Bounded a,
351+ Bounded b,
352+ Enum a,
353+ Enum b,
354+ Eq b,
355+ KnownNat (I.Count (I.Normalize a)),
356+ KnownNat (I.Count (I.Normalize b)),
357+ I.FromLists (Natural 0 1) (I.Normalize b) (I.Normalize a)
358+ ) => (a -> b -> Bool) -> Matrix (Natural 0 1) a b
359+toRel = M . I.toRel
360+
344361-- Conversion
345362
346363-- | Converts a matrix to a list of lists of elements.
src/LAoP/Relation.hsnew file+156
@@ -0,0 +1,156 @@
1+-----------------------------------------------------------------------------
2+-- |
3+-- Module : LAoP.Relation
4+-- Copyright : (c) Armando Santos 2019-2020
5+-- Maintainer : armandoifsantos@gmail.com
6+-- Stability : experimental
7+--
8+-- The AoP discipline generalises functions to relations which are
9+-- Boolean matrices.
10+--
11+-- This module offers many of the combinators of the Algebra of
12+-- Programming discipline. It is still under construction and very
13+-- experimental.
14+--
15+-- This is an Internal module and it is no supposed to be imported.
16+--
17+-----------------------------------------------------------------------------
18+
19+module LAoP.Relation
20+ ( -- | This definition makes use of the fact that 'Void' is
21+ -- isomorphic to 0 and '()' to 1 and captures matrix
22+ -- dimensions as stacks of 'Either's.
23+ --
24+ -- There exists two type families that make it easier to write
25+ -- matrix dimensions: 'FromNat' and 'Count'. This approach
26+ -- leads to a very straightforward implementation
27+ -- of LAoP combinators.
28+
29+ -- * Relation data type
30+ Relation (..),
31+ Boolean,
32+
33+ -- * Primitives
34+ empty,
35+ one,
36+ junc,
37+ (|||),
38+ split,
39+ (===),
40+
41+ -- * Auxiliary type families
42+ FromNat,
43+ Count,
44+ Normalize,
45+
46+ -- * Matrix construction and conversion
47+ FromLists,
48+ fromLists,
49+ fromF,
50+ fromF',
51+ toRel,
52+ toLists,
53+ toList,
54+ toBool,
55+ pt,
56+ belongs,
57+ relationBuilder,
58+ zeros,
59+ ones,
60+ bang,
61+ point,
62+
63+ -- * Relational operations
64+ conv,
65+ intersection,
66+ union,
67+ sse,
68+ implies,
69+ iff,
70+ ker,
71+ img,
72+
73+ -- * Taxonomy of binary relations
74+ injective,
75+ entire,
76+ simple,
77+ surjective,
78+ representation,
79+ function,
80+ abstraction,
81+ injection,
82+ surjection,
83+ bijection,
84+ domain,
85+ range,
86+
87+ -- * Function division
88+ divisionF,
89+
90+ -- * Relation division
91+ divR,
92+ divL,
93+ divS,
94+ shrunkBy,
95+ overriddenBy,
96+
97+ -- * Relational pairing
98+ splitR,
99+
100+ -- ** Projections
101+ p1,
102+ p2,
103+ -- ** Bifunctor
104+ (><),
105+ -- * Relational coproduct
106+ eitherR,
107+ -- ** Injections
108+ i1,
109+ i2,
110+ -- ** Bifunctor
111+ (-|-),
112+
113+ -- * Relational "currying"
114+ trans,
115+ untrans,
116+
117+ -- * (Endo-)Relational properties
118+ reflexive,
119+ coreflexive,
120+ transitive,
121+ symmetric,
122+ antiSymmetric,
123+ irreflexive,
124+ connected,
125+ preorder,
126+ partialOrder,
127+ linearOrder,
128+ equivalence,
129+ partialEquivalence,
130+ difunctional,
131+
132+ -- * Conditionals
133+ equalizer,
134+
135+ -- ** McCarthy's Conditional
136+ predR,
137+ guard,
138+ cond,
139+
140+ -- * Relational composition and lifting
141+ identity,
142+ comp,
143+ fromF,
144+ fromF',
145+
146+ -- ** Relational application
147+ pointAp,
148+ pointApBool,
149+
150+ -- * Matrix printing
151+ pretty,
152+ prettyPrint
153+ )
154+ where
155+
156+import LAoP.Relation.Internal
src/LAoP/Relation/Internal.hsnew file+1042
@@ -0,0 +1,1042 @@
1+{-# LANGUAGE GADTs #-}
2+{-# LANGUAGE UndecidableInstances #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE TypeApplications #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+{-# LANGUAGE StandaloneDeriving #-}
7+{-# LANGUAGE DerivingVia #-}
8+{-# LANGUAGE DataKinds #-}
9+
10+-----------------------------------------------------------------------------
11+-- |
12+-- Module : LAoP.Relation.Internal
13+-- Copyright : (c) Armando Santos 2019-2020
14+-- Maintainer : armandoifsantos@gmail.com
15+-- Stability : experimental
16+--
17+-- The AoP discipline generalises functions to relations which are
18+-- Boolean matrices.
19+--
20+-- This module offers many of the combinators of the Algebra of
21+-- Programming discipline. It is still under construction and very
22+-- experimental.
23+--
24+-- This is an Internal module and it is no supposed to be imported.
25+--
26+-----------------------------------------------------------------------------
27+
28+module LAoP.Relation.Internal
29+ ( -- | This definition makes use of the fact that 'Void' is
30+ -- isomorphic to 0 and 'One' to 1 and captures matrix
31+ -- dimensions as stacks of 'Either's.
32+ --
33+ -- There exists two type families that make it easier to write
34+ -- matrix dimensions: 'FromNat' and 'Count'. This approach
35+ -- leads to a very straightforward implementation
36+ -- of LAoP combinators.
37+
38+ -- * Relation data type
39+ Relation (..),
40+ Boolean,
41+
42+ -- * Primitives
43+ empty,
44+ one,
45+ junc,
46+ (|||),
47+ split,
48+ (===),
49+
50+ -- * Auxiliary type families
51+ I.FromNat,
52+ I.Count,
53+ I.Normalize,
54+
55+ -- * Matrix construction and conversion
56+ I.FromLists,
57+ fromLists,
58+ fromF,
59+ fromF',
60+ toRel,
61+ toLists,
62+ toList,
63+ toBool,
64+ pt,
65+ belongs,
66+ relationBuilder,
67+ zeros,
68+ ones,
69+ bang,
70+ point,
71+
72+ -- * Relational operations
73+ conv,
74+ intersection,
75+ union,
76+ sse,
77+ implies,
78+ iff,
79+ ker,
80+ img,
81+
82+ -- * Taxonomy of binary relations
83+ injective,
84+ entire,
85+ simple,
86+ surjective,
87+ representation,
88+ function,
89+ abstraction,
90+ injection,
91+ surjection,
92+ bijection,
93+ domain,
94+ range,
95+
96+ -- * Function division
97+ divisionF,
98+
99+ -- * Relation division
100+ divR,
101+ divL,
102+ divS,
103+ shrunkBy,
104+ overriddenBy,
105+
106+ -- * Relational pairing
107+ splitR,
108+
109+ -- ** Projections
110+ p1,
111+ p2,
112+ -- ** Bifunctor
113+ (><),
114+ -- * Relational coproduct
115+ eitherR,
116+ -- ** Injections
117+ i1,
118+ i2,
119+ -- ** Bifunctor
120+ (-|-),
121+
122+ -- * Relational "currying"
123+ trans,
124+ untrans,
125+
126+ -- * (Endo-)Relational properties
127+ reflexive,
128+ coreflexive,
129+ transitive,
130+ symmetric,
131+ antiSymmetric,
132+ irreflexive,
133+ connected,
134+ preorder,
135+ partialOrder,
136+ linearOrder,
137+ equivalence,
138+ partialEquivalence,
139+ difunctional,
140+
141+ -- * Conditionals
142+ equalizer,
143+
144+ -- ** McCarthy's Conditional
145+ predR,
146+ guard,
147+ cond,
148+
149+ -- * Relational composition and lifting
150+ identity,
151+ comp,
152+ fromF,
153+ fromF',
154+
155+ -- ** Relational application
156+ pointAp,
157+ pointApBool,
158+
159+ -- * Matrix printing
160+ pretty,
161+ prettyPrint
162+ )
163+ where
164+
165+import Data.Void
166+import qualified LAoP.Matrix.Internal as I
167+import LAoP.Utils.Internal
168+import Control.DeepSeq
169+import qualified Control.Category as C
170+import Data.Bool
171+import GHC.TypeLits
172+
173+-- | Boolean type synonym for working with boolean matrices
174+type Boolean = Natural 0 1
175+
176+-- | Relation data type.
177+newtype Relation a b = R (I.Matrix Boolean (I.Normalize a) (I.Normalize b))
178+ deriving (Show, Eq, Ord, NFData) via (I.Matrix (Natural 1 1) (I.Normalize a) (I.Normalize b))
179+
180+deriving instance (Read (I.Matrix Boolean (I.Normalize a) (I.Normalize b))) => Read (Relation a b)
181+
182+-- | It isn't possible to implement the 'id' function so it's
183+-- implementation is 'undefined'. However 'comp' can be and this partial
184+-- class implementation exists just to make the code more readable.
185+--
186+-- Please use 'identity' instead.
187+instance C.Category Relation where
188+ id = undefined
189+ (.) = comp
190+
191+instance Num (Relation a b) where
192+ -- | Matrix addition becomes Boolean matrix disjunction
193+ (R a) + (R b) = R (I.orM a b)
194+
195+ -- | Matrix subtraction becomes Relational subtraction
196+ (R a) - (R b) = R (I.subM a b)
197+
198+ -- | Matrix multiplication becomes Boolean matrix conjunction
199+ (R a) * (R b) = R (I.andM a b)
200+
201+ -- | Matrix negation becomes Boolean matrix negation
202+ negate (R a) = R (I.negateM a)
203+
204+-- Type alias
205+type Zero = Void
206+type One = ()
207+
208+-- Primitives
209+
210+-- | Empty matrix constructor
211+empty :: Relation Zero Zero
212+empty = R I.Empty
213+
214+-- | Unit matrix constructor
215+one :: Boolean -> Relation One One
216+one = R . I.One
217+
218+-- | Boolean Matrix 'Junc' constructor, also known as relational coproduct.
219+--
220+-- See 'eitherR'.
221+junc :: (I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b))
222+ => Relation a c -> Relation b c -> Relation (Either a b) c
223+junc (R a) (R b) = R (I.Junc a b)
224+
225+infixl 3 |||
226+-- | Boolean Matrix 'Junc' constructor
227+--
228+-- See 'eitherR'.
229+(|||) ::
230+ (I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b)) =>
231+ Relation a c ->
232+ Relation b c ->
233+ Relation (Either a b) c
234+(|||) = junc
235+
236+-- | Boolean Matrix 'Split' constructor, also known as relational product.
237+split :: (I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b))
238+ => Relation c a -> Relation c b -> Relation c (Either a b)
239+split (R a) (R b) = R (I.Split a b)
240+
241+infixl 2 ===
242+-- | Boolean Matrix 'Split' constructor
243+(===) ::
244+ (I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b)) =>
245+ Relation c a ->
246+ Relation c b ->
247+ Relation c (Either a b)
248+(===) = split
249+
250+-- Construction
251+
252+-- | Build a matrix out of a list of list of elements. Throws a runtime
253+-- error if the dimensions do not match.
254+fromLists :: (I.FromLists Boolean (I.Normalize a) (I.Normalize b)) => [[Boolean]] -> Relation a b
255+fromLists = R . I.fromLists
256+
257+-- | Matrix builder function. Constructs a matrix provided with
258+-- a construction function.
259+relationBuilder ::
260+ (I.FromLists Boolean (I.Normalize a) (I.Normalize b), KnownNat (I.Count (I.Normalize a)), KnownNat (I.Count (I.Normalize b))) =>
261+ ((Int, Int) -> Boolean) ->
262+ Relation a b
263+relationBuilder = R . I.matrixBuilder
264+
265+-- | Lifts functions to matrices with arbitrary dimensions.
266+--
267+-- NOTE: Be careful to not ask for a matrix bigger than the cardinality of
268+-- types @a@ or @b@ allows.
269+fromF ::
270+ ( Bounded a,
271+ Bounded b,
272+ Enum a,
273+ Enum b,
274+ Eq b,
275+ KnownNat (I.Count (I.Normalize c)),
276+ KnownNat (I.Count (I.Normalize d)),
277+ I.FromLists Boolean (I.Normalize d) (I.Normalize c)
278+ )
279+ => (a -> b) -> Relation c d
280+fromF f = R (I.fromFRel f)
281+
282+-- | Lifts functions to matrices with dimensions matching @a@ and @b@
283+-- cardinality's.
284+fromF' ::
285+ ( Bounded b,
286+ Bounded a,
287+ Enum a,
288+ Enum b,
289+ Eq b,
290+ KnownNat (I.Count (I.Normalize a)),
291+ KnownNat (I.Count (I.Normalize b)),
292+ I.FromLists Boolean (I.Normalize b) (I.Normalize a)
293+ )
294+ => (a -> b) -> Relation a b
295+fromF' f = R (I.fromFRel' f)
296+
297+-- | Lifts relation functions to 'Relation'
298+toRel ::
299+ ( Bounded b,
300+ Bounded a,
301+ Enum a,
302+ Enum b,
303+ Eq b,
304+ KnownNat (I.Count (I.Normalize a)),
305+ KnownNat (I.Count (I.Normalize b)),
306+ I.FromLists Boolean (I.Normalize b) (I.Normalize a)
307+ )
308+ => (a -> b -> Bool) -> Relation a b
309+toRel = R . I.toRel
310+
311+-- | Lowers a 'Relation' to a function
312+fromRel ::
313+ ( Bounded a,
314+ Bounded b,
315+ Enum a,
316+ Enum b,
317+ Eq a,
318+ Eq b,
319+ KnownNat (I.Count (I.Normalize a)),
320+ KnownNat (I.Count (I.Normalize b)),
321+ I.FromLists Boolean (I.Normalize a) One,
322+ I.FromLists Boolean (I.Normalize b) One
323+ )
324+ => Relation a b -> (a -> b -> Bool)
325+fromRel r a b = pointApBool a b r
326+
327+-- Conversion
328+
329+-- | Converts a matrix to a list of lists of elements.
330+toLists :: Relation a b -> [[Boolean]]
331+toLists (R m) = I.toLists m
332+
333+-- | Converts a matrix to a list of elements.
334+toList :: Relation a b -> [Boolean]
335+toList (R m) = I.toList m
336+
337+-- | Converts a well typed 'Relation' to 'Bool'.
338+toBool :: Relation One One -> Bool
339+toBool r = case toList r of
340+ [Nat 0] -> False
341+ _ -> True
342+
343+-- | Power transpose.
344+--
345+-- Maps a relation to a set valued function.
346+pt ::
347+ ( Bounded a,
348+ Bounded b,
349+ Enum a,
350+ Enum b,
351+ Eq a,
352+ Eq b,
353+ KnownNat (I.Count (I.Normalize a)),
354+ KnownNat (I.Count (I.Normalize b)),
355+ I.FromLists Boolean (I.Normalize a) One,
356+ I.FromLists Boolean (I.Normalize b) One
357+ )
358+ => Relation a b -> (a -> Powerset b)
359+pt r a =
360+ let (PS lb) = maxBound
361+ in PS [ b | b <- lb, toBool (pointAp a b r) ]
362+
363+-- | Belongs relation
364+belongs ::
365+ ( Bounded a,
366+ Enum a,
367+ Eq a,
368+ KnownNat (I.Count (I.Normalize (Powerset a))),
369+ KnownNat (I.Count (I.Normalize a)),
370+ I.FromLists Boolean (I.Normalize a) (I.Normalize (Powerset a))
371+ )
372+ => Relation (Powerset a) a
373+belongs = toRel (flip elemR)
374+ where
375+ elemR x (PS l) = x `elem` l
376+
377+-- Zeros Matrix
378+
379+-- | The zero relation. A relation where no element of type @a@ relates
380+-- with elements of type @b@.
381+--
382+-- Also known as ⊥ (Bottom) Relation or empty Relation.
383+--
384+-- @
385+-- r ``comp`` ⊥ == ⊥ ``comp`` r == ⊥
386+-- ⊥ ``sse`` R && R ``sse`` T == True
387+-- @
388+zeros ::
389+ (I.FromLists Boolean (I.Normalize a) (I.Normalize b), KnownNat (I.Count (I.Normalize a)), KnownNat (I.Count (I.Normalize b))) =>
390+ Relation a b
391+zeros = relationBuilder (const (nat 0))
392+
393+-- Ones Matrix
394+
395+-- | The ones relation. A relation where every element of type @a@ relates
396+-- with every element of type @b@.
397+--
398+-- Also known as T (Top) Relation or universal Relation.
399+--
400+-- @
401+-- ⊥ ``sse`` R && R ``sse`` T == True
402+-- @
403+ones ::
404+ (I.FromLists Boolean (I.Normalize a) (I.Normalize b), KnownNat (I.Count (I.Normalize a)), KnownNat (I.Count (I.Normalize b))) =>
405+ Relation a b
406+ones = relationBuilder (const (nat 1))
407+
408+-- Bang Matrix
409+
410+-- | The T (Top) row vector relation.
411+bang ::
412+ (I.FromLists Boolean (I.Normalize a) One, KnownNat (I.Count (I.Normalize a))) =>
413+ Relation a One
414+bang = ones
415+
416+-- | Point constant relation
417+point ::
418+ ( Bounded a,
419+ Enum a,
420+ Eq a,
421+ KnownNat (I.Count (I.Normalize a)),
422+ I.FromLists Boolean (I.Normalize a) One
423+ ) => a -> Relation One a
424+point = fromF' . const
425+
426+-- Identity Matrix
427+
428+-- | Identity matrix
429+--
430+-- @
431+-- 'identity' ``comp`` r == r == r ``comp`` 'identity'
432+-- @
433+identity ::
434+ (I.FromLists Boolean (I.Normalize a) (I.Normalize a), KnownNat (I.Count (I.Normalize a))) =>
435+ Relation a a
436+identity = relationBuilder (bool (nat 0) (nat 1) . uncurry (==))
437+
438+-- | Relational composition
439+--
440+-- @
441+-- r ``comp`` (s ``comp`` p) = (r ``comp`` s) ``comp`` p
442+-- @
443+comp :: Relation b c -> Relation a b -> Relation a c
444+comp (R a) (R b) = R (I.compRel a b)
445+
446+-- | Relational right division
447+--
448+-- @'divR' x y@ is the largest relation @z@ which,
449+-- pre-composed with @y@, approximates @x@.
450+divR :: Relation b c -> Relation b a -> Relation a c
451+divR (R x) (R y) = R (I.divR x y)
452+
453+-- | Relational left division
454+--
455+-- The dual division operator:
456+--
457+-- @
458+-- 'divL' y x == 'conv' ('divR' ('conv' x) ('conv' y)
459+-- @
460+divL :: Relation c b -> Relation a b -> Relation a c
461+divL (R x) (R y) = R (I.divL x y)
462+
463+-- | Relational symmetric division
464+--
465+-- @'pointAp' c b ('divS' s r)@ means that @b@ and @c@
466+-- are related to exactly the same outputs by @r@ and by @s@.
467+divS :: Relation c a -> Relation b a -> Relation c b
468+divS (R x) (R y) = R (I.divS x y)
469+
470+-- | Relational shrinking.
471+--
472+-- @r ``shrunkBy`` s@ is the largest part of @r@ such that,
473+-- if it yields an output for an input @x@, it must be a maximum,
474+-- with respect to @s@, among all possible outputs of @x@ by @r@.
475+shrunkBy :: Relation b a -> Relation a a -> Relation b a
476+shrunkBy r s = r `intersection` divR s (conv r)
477+
478+-- | Relational overriding.
479+--
480+-- @r ``overriddenBy`` s@ yields the relation which contains the
481+-- whole of @s@ and that part of @r@ where @s@ is undefined.
482+--
483+-- @
484+-- 'zeros' ``overriddenBy`` s == s
485+-- r ``overriddenBy`` 'zeros' == r
486+-- r ``overriddenBy`` r == r
487+-- @
488+overriddenBy ::
489+ ( I.FromLists Boolean (I.Normalize b) (I.Normalize b),
490+ KnownNat (I.Count (I.Normalize b))
491+ ) => Relation a b -> Relation a b -> Relation a b
492+overriddenBy r s = s `union` r `intersection` divR zeros (conv s)
493+
494+-- | Relational application.
495+--
496+-- If @a@ and @b@ are related by 'Relation' @r@
497+-- then @'pointAp' a b r == 'one' ('nat' 1)@
498+pointAp ::
499+ ( Bounded a,
500+ Bounded b,
501+ Enum a,
502+ Enum b,
503+ Eq a,
504+ Eq b,
505+ KnownNat (I.Count (I.Normalize a)),
506+ KnownNat (I.Count (I.Normalize b)),
507+ I.FromLists Boolean (I.Normalize a) One,
508+ I.FromLists Boolean (I.Normalize b) One
509+ ) => a -> b -> Relation a b -> Relation One One
510+pointAp a b r = conv (point b) `comp` r `comp` point a
511+
512+-- | Relational application
513+--
514+-- The same as 'pointAp' but converts 'Boolean' to 'Bool'
515+pointApBool ::
516+ ( Bounded a,
517+ Bounded b,
518+ Enum a,
519+ Enum b,
520+ Eq a,
521+ Eq b,
522+ KnownNat (I.Count (I.Normalize a)),
523+ KnownNat (I.Count (I.Normalize b)),
524+ I.FromLists Boolean (I.Normalize a) One,
525+ I.FromLists Boolean (I.Normalize b) One
526+ ) => a -> b -> Relation a b -> Bool
527+pointApBool a b r = toBool $ conv (point b) `comp` r `comp` point a
528+
529+-- | Relational converse
530+--
531+-- Given binary 'Relation' r, writing @'pointAp' a b r@
532+-- (read: “@b@ is related to @a@ by @r@”) means the same as
533+-- @'pointAp' b a ('conv' r)@, where @'conv' r@ is said to be
534+-- the converse of @r@.
535+-- In terms of grammar, @'conv' r@ corresponds to the passive voice
536+conv :: Relation a b -> Relation b a
537+conv (R a) = R (I.tr a)
538+
539+-- | Relational inclusion (subset or equal)
540+sse :: Relation a b -> Relation a b -> Bool
541+sse a b = a <= b
542+
543+-- | Relational implication (the same as @'sse'@)
544+implies :: Relation a b -> Relation a b -> Relation a b
545+implies r s = negate r `union` s
546+
547+-- | Relational bi-implication
548+iff :: Relation a b -> Relation a b -> Bool
549+iff r s = r == s
550+
551+-- | Relational intersection
552+--
553+-- Lifts pointwise conjunction.
554+--
555+-- @
556+-- (r ``intersection`` s) ``intersection`` t == r ``intersection`` (s ``intersection`` t)
557+-- x ``sse`` r ``intersection`` s == x ``intersection`` r && x ``intersection`` s
558+-- @
559+intersection :: Relation a b -> Relation a b -> Relation a b
560+intersection a b = a * b
561+
562+-- | Relational union
563+--
564+-- Lifts pointwise disjunction.
565+--
566+-- @
567+-- (r ``union`` s) ``union`` t == r `'union' (s ``union`` t)
568+-- r ``union`` s ``sse`` x == r ``sse`` x && s ``sse`` x
569+-- r ``comp`` (s ``union`` t) == (r ``comp`` s) ``union`` (r ``comp`` t)
570+-- (s ``union`` t) ``comp`` r == (s ``comp`` r) ``union`` (t ``comp`` r)
571+-- @
572+union :: Relation a b -> Relation a b -> Relation a b
573+union a b = a + b
574+
575+-- | Relation Kernel
576+--
577+-- @
578+-- 'ker' r == 'conv' r ``comp`` r
579+-- 'ker' r == 'img' ('conv' r)
580+-- @
581+ker :: Relation a b -> Relation a a
582+ker r = conv r `comp` r
583+
584+-- | Relation Image
585+--
586+-- @
587+-- 'img' r == r ``comp`` conv r
588+-- 'img' r == 'ker' ('conv' r)
589+-- @
590+img :: Relation a b -> Relation b b
591+img r = r `comp` conv r
592+
593+-- | Function division. Special case of 'divS'.
594+--
595+-- NOTE: _This is only valid_ if @f@ and @g@ are 'function's, i.e. 'simple' and
596+-- 'entire'.
597+--
598+-- @'divisionF' f g == 'conv' g ``comp`` f@
599+divisionF :: Relation a c -> Relation b c -> Relation a b
600+divisionF f g = conv g `comp` f
601+
602+-- Taxonomy of binary relations
603+
604+-- | A 'Relation' @r@ is 'simple' 'iff' @'coreflexive' ('img' r)@
605+simple :: (KnownNat (I.Count (I.Normalize b)), I.FromLists Boolean (I.Normalize b) (I.Normalize b)) => Relation a b -> Bool
606+simple = coreflexive . img
607+
608+-- | A 'Relation' @r@ is 'injective' 'iff' @'coreflexive' ('ker' r)@
609+injective :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a b -> Bool
610+injective = coreflexive . ker
611+
612+-- | A 'Relation' @r@ is 'entire' 'iff' @'reflexive' ('ker' r)@
613+entire :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a b -> Bool
614+entire = reflexive . ker
615+
616+-- | A 'Relation' @r@ is 'surjective' 'iff' @'reflexive' ('img' r)@
617+surjective :: (KnownNat (I.Count (I.Normalize b)), I.FromLists Boolean (I.Normalize b) (I.Normalize b)) => Relation a b -> Bool
618+surjective = reflexive . img
619+
620+-- | A 'Relation' @r@ is a 'function' 'iff' @'simple' r && 'entire' r@
621+--
622+-- A 'function' @f@ enjoys the following properties, where @r@ and @s@ are binary
623+-- relations:
624+--
625+-- @
626+-- f ``comp`` r ``sse`` s == r ``sse`` f ``comp`` s
627+-- r ``comp`` f ``sse`` s == r ``sse`` s ``comp`` f
628+-- @
629+function ::
630+ ( KnownNat (I.Count (I.Normalize b)),
631+ KnownNat (I.Count (I.Normalize a)),
632+ I.FromLists Boolean (I.Normalize a) (I.Normalize a),
633+ I.FromLists Boolean (I.Normalize b) (I.Normalize b)
634+ )
635+ => Relation a b -> Bool
636+function r = simple r && entire r
637+
638+-- | A 'Relation' @r@ is a 'representation' 'iff' @'injective' r && 'entire' r@
639+representation ::
640+ ( KnownNat (I.Count (I.Normalize a)),
641+ I.FromLists Boolean (I.Normalize a) (I.Normalize a)
642+ )
643+ => Relation a b -> Bool
644+representation r = injective r && entire r
645+
646+-- | A 'Relation' @r@ is an 'abstraction' 'iff' @'surjective' r && 'simple' r@
647+abstraction ::
648+ ( KnownNat (I.Count (I.Normalize b)),
649+ I.FromLists Boolean (I.Normalize b) (I.Normalize b)
650+ )
651+ => Relation a b -> Bool
652+abstraction r = surjective r && simple r
653+
654+-- | A 'Relation' @r@ is a 'surjection' 'iff' @'function' r && 'abstraction' r@
655+surjection ::
656+ ( KnownNat (I.Count (I.Normalize b)),
657+ KnownNat (I.Count (I.Normalize a)),
658+ I.FromLists Boolean (I.Normalize a) (I.Normalize a),
659+ I.FromLists Boolean (I.Normalize b) (I.Normalize b)
660+ )
661+ => Relation a b -> Bool
662+surjection r = function r && abstraction r
663+
664+-- | A 'Relation' @r@ is a 'injection' 'iff' @'function' r && 'representation' r@
665+injection ::
666+ ( KnownNat (I.Count (I.Normalize b)),
667+ KnownNat (I.Count (I.Normalize a)),
668+ I.FromLists Boolean (I.Normalize a) (I.Normalize a),
669+ I.FromLists Boolean (I.Normalize b) (I.Normalize b)
670+ )
671+ => Relation a b -> Bool
672+injection r = function r && representation r
673+
674+-- | A 'Relation' @r@ is an 'bijection' 'iff' @'injection' r && 'surjection' r@
675+bijection ::
676+ ( KnownNat (I.Count (I.Normalize b)),
677+ KnownNat (I.Count (I.Normalize a)),
678+ I.FromLists Boolean (I.Normalize b) (I.Normalize b),
679+ I.FromLists Boolean (I.Normalize a) (I.Normalize a)
680+ ) => Relation a b -> Bool
681+bijection r = injection r && surjection r
682+
683+
684+-- Properties of relations
685+
686+-- | A 'Relation' @r@ is 'reflexive' 'iff' @'identity' ``sse`` r@
687+reflexive :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
688+reflexive r = identity <= r
689+
690+-- | A 'Relation' @r@ is 'coreflexive' 'iff' @r ``sse`` 'identity'@
691+coreflexive :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
692+coreflexive r = r <= identity
693+
694+-- | A 'Relation' @r@ is 'transitive' 'iff' @(r ``comp`` r) ``sse`` r@
695+transitive :: Relation a a -> Bool
696+transitive r = (r `comp` r) `sse` r
697+
698+-- | A 'Relation' @r@ is 'symmetric' 'iff' @r == 'conv' r@
699+symmetric :: Relation a a -> Bool
700+symmetric r = r == conv r
701+
702+-- | A 'Relation' @r@ is anti-symmetric 'iff' @(r ``intersection`` 'conv' r) ``sse`` 'identity'@
703+antiSymmetric :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
704+antiSymmetric r = (r `intersection` conv r) `sse` identity
705+
706+-- | A 'Relation' @r@ is 'irreflexive' 'iff' @(r ``intersection`` 'identity') == 'zeros'@
707+irreflexive :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
708+irreflexive r = (r `intersection` identity) == zeros
709+
710+-- | A 'Relation' @r@ is 'connected' 'iff' @(r ``union`` 'conv' r) == 'ones'@
711+connected :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
712+connected r = (r `union` conv r) == ones
713+
714+-- | A 'Relation' @r@ is a 'preorder' 'iff' @'reflexive' r && 'transitive' r@
715+preorder :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
716+preorder r = reflexive r && transitive r
717+
718+-- | A 'Relation' @r@ is a partial-order 'iff' @'antiSymmetric' r && 'preorder' r@
719+partialOrder :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
720+partialOrder r = antiSymmetric r && preorder r
721+
722+-- | A 'Relation' @r@ is a linear-order 'iff' @'connected' r && 'partialOrder' r@
723+linearOrder :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
724+linearOrder r = connected r && partialOrder r
725+
726+-- | A 'Relation' @r@ is an 'equivalence' 'iff' @'symmetric' r && 'preorder' r@
727+equivalence :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
728+equivalence r = symmetric r && preorder r
729+
730+-- | A 'Relation' @r@ is a partial-equivalence 'iff' @'partialOrder' r && 'equivalence' r@
731+partialEquivalence :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
732+partialEquivalence r = partialOrder r && equivalence r
733+
734+-- | A 'Relation' @r@ is 'difunctional' or regular wherever
735+-- @r ``comp`` 'conv' r ``comp`` r == r@
736+difunctional :: Relation a b -> Bool
737+difunctional r = r `comp` conv r `comp` r == r
738+
739+-- Relational pairing
740+
741+-- | Relational pairing.
742+--
743+-- NOTE: That this is not a true categorical product, see for instance:
744+--
745+-- @
746+-- | 'p1' ``comp`` 'splitR' a b ``sse`` a
747+-- 'splitR' a b <=> |
748+-- | 'p2' ``comp`` 'splitR' a b ``sse`` b
749+-- @
750+--
751+-- __Emphasis__ on the 'sse'.
752+--
753+-- @
754+-- 'splitR' r s ``comp`` f == 'splitR' (r ``comp`` f) (s ``comp`` f)
755+-- (R '><' S) ``comp`` 'splitR' p q == 'splitR' (r ``comp`` p) (s ``comp`` q)
756+-- 'conv' ('splitR' r s) ``comp`` 'splitR' x y == ('conv' r ``comp`` x) ``intersection`` ('conv' s ``comp`` y)
757+-- @
758+--
759+-- @
760+-- 'eitherR' ('splitR' r s) ('splitR' t v) == 'splitR' ('eitherR' r t) ('eitherR' s v)
761+-- @
762+splitR ::
763+ ( KnownNat (I.Count (I.Normalize a)),
764+ KnownNat (I.Count (I.Normalize b)),
765+ KnownNat (I.Count (I.Normalize (a, b))),
766+ I.FromLists Boolean (I.Normalize (a, b)) (I.Normalize a),
767+ I.FromLists Boolean (I.Normalize (a, b)) (I.Normalize b),
768+ I.Normalize (a, b) ~ I.Normalize (I.Normalize a, I.Normalize b)
769+ )
770+ => Relation c a -> Relation c b -> Relation c (a, b)
771+splitR (R f) (R g) = R (I.khatri f g)
772+
773+-- | Relational pairing first component projection
774+--
775+-- @
776+-- 'p1' ``comp`` 'splitR' r s ``sse`` r
777+-- @
778+p1 ::
779+ forall a b .
780+ ( KnownNat (I.Count (I.Normalize a)),
781+ KnownNat (I.Count (I.Normalize b)),
782+ KnownNat (I.Count (I.Normalize (a, b))),
783+ I.FromLists Boolean (I.Normalize (a, b)) (I.Normalize a),
784+ I.Normalize (a, b) ~ I.Normalize (I.Normalize a, I.Normalize b)
785+ )
786+ => Relation (a, b) a
787+p1 = R (I.kp1 @Boolean @(I.Normalize a) @(I.Normalize b))
788+
789+-- | Relational pairing second component projection
790+--
791+-- @
792+-- 'p2' ``comp`` 'splitR' r s ``sse`` s
793+-- @
794+p2 ::
795+ forall a b .
796+ ( KnownNat (I.Count (I.Normalize b)),
797+ KnownNat (I.Count (I.Normalize a)),
798+ KnownNat (I.Count (I.Normalize (a, b))),
799+ I.FromLists Boolean (I.Normalize (a, b)) (I.Normalize b),
800+ I.Normalize (a, b) ~ I.Normalize (I.Normalize a, I.Normalize b)
801+ )
802+ => Relation (a, b) b
803+p2 = R (I.kp2 @Boolean @(I.Normalize a) @(I.Normalize b))
804+
805+-- Relational pairing functor
806+
807+infixl 4 ><
808+-- | Relational pairing functor
809+--
810+-- @
811+-- r '><' s == 'splitR' (r ``comp`` p1) (s ``comp`` p2)
812+-- (r '><' s) ``comp`` (p '><' q) == (r ``comp`` p) '><' (s ``comp`` q)
813+-- @
814+(><) ::
815+ ( KnownNat (I.Count (I.Normalize a)),
816+ KnownNat (I.Count (I.Normalize b)),
817+ KnownNat (I.Count (I.Normalize c)),
818+ KnownNat (I.Count (I.Normalize d)),
819+ KnownNat (I.Count (I.Normalize (a, c))),
820+ KnownNat (I.Count (I.Normalize (b, d))),
821+ I.FromLists Boolean (I.Normalize (a, c)) (I.Normalize a),
822+ I.FromLists Boolean (I.Normalize (a, c)) (I.Normalize c),
823+ I.FromLists Boolean (I.Normalize (b, d)) (I.Normalize b),
824+ I.FromLists Boolean (I.Normalize (b, d)) (I.Normalize d),
825+ I.Normalize (a, c) ~ I.Normalize (I.Normalize a, I.Normalize c),
826+ I.Normalize (b, d) ~ I.Normalize (I.Normalize b, I.Normalize d)
827+ )
828+ => Relation a b -> Relation c d -> Relation (a, c) (b, d)
829+(><) (R a) (R b) = R ((I.><) a b)
830+
831+-- Relational co-products
832+
833+-- | Relational coproduct.
834+--
835+-- @
836+-- | 'eitherR' a b ``comp`` 'i1' == a
837+-- 'eitherR' a b <=> |
838+-- | 'eitherR' a b ``comp`` 'i2' == b
839+-- @
840+--
841+-- @
842+-- 'eitherR' r s ``comp`` 'conv' ('eitherR' t u) == (r ``comp`` 'conv' t) ``union`` (s ``comp`` 'conv' u)
843+-- @
844+--
845+-- @
846+-- 'eitherR' ('splitR' r s) ('splitR' t v) == 'splitR' ('eitherR' r t) ('eitherR' s v)
847+-- @
848+eitherR :: (I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b))
849+ => Relation a c -> Relation b c -> Relation (Either a b) c
850+eitherR = junc
851+
852+-- | Relational coproduct first component injection
853+--
854+-- @
855+-- 'img' 'i1' ``union`` 'img' 'i2' == 'identity'
856+-- 'i1' ``comp`` 'i2' = 'zeros'
857+-- @
858+i1 ::
859+ ( KnownNat (I.Count (I.Normalize b)),
860+ KnownNat (I.Count (I.Normalize a)),
861+ I.FromLists Boolean (I.Normalize b) (I.Normalize a),
862+ I.FromLists Boolean (I.Normalize a) (I.Normalize a),
863+ I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b)
864+ )
865+ => Relation a (Either a b)
866+i1 = R I.i1
867+
868+-- | Relational coproduct second component injection
869+--
870+-- @
871+-- 'img' 'i1' ``union`` 'img' 'i2' == 'identity'
872+-- 'i1' ``comp`` 'i2' = 'zeros'
873+-- @
874+i2 ::
875+ ( KnownNat (I.Count (I.Normalize b)),
876+ KnownNat (I.Count (I.Normalize a)),
877+ I.FromLists Boolean (I.Normalize a) (I.Normalize b),
878+ I.FromLists Boolean (I.Normalize b) (I.Normalize b),
879+ I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b)
880+ )
881+ => Relation b (Either a b)
882+i2 = R I.i2
883+
884+infixl 5 -|-
885+
886+-- | Relational coproduct functor.
887+--
888+-- @
889+-- r '-|-' s == 'eitherR' ('i1' ``comp`` r) ('i2' ``comp`` s)
890+-- @
891+(-|-) ::
892+ ( KnownNat (I.Count (I.Normalize d)),
893+ KnownNat (I.Count (I.Normalize b)),
894+ I.FromLists Boolean (I.Normalize b) (I.Normalize b),
895+ I.FromLists Boolean (I.Normalize d) (I.Normalize b),
896+ I.FromLists Boolean (I.Normalize b) (I.Normalize d),
897+ I.FromLists Boolean (I.Normalize d) (I.Normalize d),
898+ I.Normalize (Either a c) ~ Either (I.Normalize a) (I.Normalize c),
899+ I.Normalize (Either b d) ~ Either (I.Normalize b) (I.Normalize d)
900+ )
901+ => Relation a b -> Relation c d -> Relation (Either a c) (Either b d)
902+(-|-) (R a) (R b) = R ((I.-|-) a b)
903+
904+-- Relational "Currying"
905+
906+-- | Relational 'trans'
907+--
908+-- Every n-ary relation can be expressed as a binary relation through
909+-- 'trans'/'untrans';
910+-- more-over, where each particular attribute is placed (input/output) is irrelevant.
911+trans ::
912+ ( KnownNat (I.Count (I.Normalize (a, b))),
913+ KnownNat (I.Count (I.Normalize a)),
914+ KnownNat (I.Count (I.Normalize (c, b))),
915+ KnownNat (I.Count (I.Normalize b)),
916+ KnownNat (I.Count (I.Normalize c)),
917+ I.FromLists Boolean (I.Normalize (c, b)) (I.FromNat (I.Count c)),
918+ I.FromLists Boolean (I.Normalize (c, b)) (I.FromNat (I.Count b)),
919+ I.FromLists Boolean (I.Normalize (a, b)) (I.FromNat (I.Count b)),
920+ I.FromLists Boolean (I.Normalize (a, b)) (I.FromNat (I.Count a)),
921+ I.Normalize (a, b) ~ I.Normalize (I.Normalize (a, b)),
922+ I.Normalize (c, b) ~ I.Normalize (I.Normalize (c, b)),
923+ I.Normalize (I.Normalize a, I.Normalize b) ~ I.FromNat (I.Count (I.Normalize (a, b))),
924+ I.Normalize (I.Normalize c, I.Normalize b) ~ I.FromNat (I.Count (I.Normalize (c, b)))
925+ )
926+ => Relation (a, b) c -> Relation a (c, b)
927+trans r = splitR r p2 `comp` conv p1
928+
929+-- | Relational 'untrans'
930+--
931+-- Every n-ary relation can be expressed as a binary relation through
932+-- 'trans'/'untrans';
933+-- more-over, where each particular attribute is placed (input/output) is irrelevant.
934+untrans ::
935+ ( KnownNat (I.Count (I.Normalize (a, b))),
936+ KnownNat (I.Count (I.Normalize a)),
937+ KnownNat (I.Count (I.Normalize (c, b))),
938+ KnownNat (I.Count (I.Normalize b)),
939+ KnownNat (I.Count (I.Normalize c)),
940+ I.FromLists Boolean (I.Normalize (c, b)) (I.FromNat (I.Count c)),
941+ I.FromLists Boolean (I.Normalize (c, b)) (I.FromNat (I.Count b)),
942+ I.FromLists Boolean (I.Normalize (a, b)) (I.FromNat (I.Count b)),
943+ I.FromLists Boolean (I.Normalize (a, b)) (I.FromNat (I.Count a)),
944+ I.Normalize (a, b) ~ I.Normalize (I.Normalize (a, b)),
945+ I.Normalize (c, b) ~ I.Normalize (I.Normalize (c, b)),
946+ I.Normalize (I.Normalize a, I.Normalize b) ~ I.FromNat (I.Count (I.Normalize (a, b))),
947+ I.Normalize (I.Normalize c, I.Normalize b) ~ I.FromNat (I.Count (I.Normalize (c, b)))
948+ )
949+ => Relation a (c, b) -> Relation (a, b) c
950+untrans s = p1 `comp` conv (splitR (conv s) p2)
951+
952+-- | Transforms predicate @p@ into a correflexive relation.
953+--
954+-- @
955+-- 'predR' ('const' True) == 'identity'
956+-- 'predR' ('const' False) == 'zeros'
957+-- @
958+--
959+-- @
960+-- 'predR' q ``comp`` 'predR' p == 'predR' q ``union`` 'predR' p
961+-- @
962+predR ::
963+ ( Bounded a,
964+ Enum a,
965+ KnownNat (I.Count (I.Normalize a)),
966+ I.FromLists Boolean (I.Normalize a) (I.Normalize a),
967+ I.FromLists Boolean (I.Normalize Bool) (I.Normalize a)
968+ )
969+ => (a -> Bool) -> Relation a a
970+predR p = identity `intersection` divisionF (fromF' (const True)) (fromF' p)
971+
972+-- | Equalizes functions @f@ and @g@.
973+-- That is, @'equalizer' f g@ is the largest coreflexive
974+-- that restricts @g@ so that @f@ and @g@ yield the same outputs.
975+--
976+-- @
977+-- 'equalizer' r r == 'identity'
978+-- 'equalizer' ('point' True) ('point' False) == 'zeros'
979+-- @
980+equalizer ::
981+ ( KnownNat (I.Count (I.Normalize a)),
982+ I.FromLists Boolean (I.Normalize a) (I.Normalize a)
983+ )
984+ => Relation a b -> Relation a b -> Relation a a
985+equalizer f g = identity `intersection` divisionF f g
986+
987+-- | Relational conditional guard.
988+--
989+-- @
990+-- 'guard' p = 'i2' ``overriddenBy`` 'i1' ``comp`` 'predR' p
991+-- @
992+guard ::
993+ ( Bounded b,
994+ Enum b,
995+ KnownNat (I.Count (I.Normalize b)),
996+ I.FromLists Boolean (I.Normalize b) (I.Normalize b),
997+ I.FromLists Boolean (I.Normalize Bool) (I.Normalize b),
998+ I.Normalize (Either b b) ~ Either (I.Normalize b) (I.Normalize b)
999+ ) => (b -> Bool) -> Relation b (Either b b)
1000+guard p = conv (eitherR (predR p) (predR (not . p)))
1001+
1002+-- | Relational McCarthy's conditional.
1003+cond ::
1004+ ( Bounded b,
1005+ Enum b,
1006+ KnownNat (I.Count (I.Normalize b)),
1007+ I.FromLists Boolean (I.Normalize b) (I.Normalize b),
1008+ I.FromLists Boolean (I.Normalize Bool) (I.Normalize b),
1009+ I.Normalize (Either b b) ~ Either (I.Normalize b) (I.Normalize b)
1010+ )
1011+ => (b -> Bool) -> Relation b c -> Relation b c -> Relation b c
1012+cond p r s = eitherR r s `comp` guard p
1013+
1014+-- | Relational domain.
1015+--
1016+-- For injective relations, 'domain' and 'ker'nel coincide,
1017+-- since @'ker' r ``sse`` 'identity'@ in such situations.
1018+domain ::
1019+ ( KnownNat (I.Count (I.Normalize a)),
1020+ I.FromLists Boolean (I.Normalize a) (I.Normalize a)
1021+ ) => Relation a b -> Relation a a
1022+domain r = ker r `intersection` identity
1023+
1024+-- | Relational range.
1025+--
1026+-- For functions, 'range' and 'img' (image) coincide,
1027+-- since @'img' f ``sse`` 'identity'@ for any @f@.
1028+range ::
1029+ ( I.FromLists Boolean (I.Normalize b) (I.Normalize b),
1030+ KnownNat (I.Count (I.Normalize b))
1031+ ) => Relation a b -> Relation b b
1032+range r = img r `intersection` identity
1033+
1034+-- Relation pretty print
1035+
1036+-- | Relation pretty printing
1037+pretty :: (KnownNat (I.Count (I.Normalize a))) => Relation a b -> String
1038+pretty (R a) = I.pretty a
1039+
1040+-- | Relation pretty printing
1041+prettyPrint :: (KnownNat (I.Count (I.Normalize a))) => Relation a b -> IO ()
1042+prettyPrint (R a) = I.prettyPrint a
src/Utils.hs → src/LAoP/Utils.hsrenamed+6−3
@@ -1,6 +1,6 @@
11-----------------------------------------------------------------------------
22-- |
3−-- Module : Utils
3+-- Module : LAoP.Utils
44-- Copyright : (c) Armando Santos 2019-2020
55-- Maintainer : armandoifsantos@gmail.com
66-- Stability : experimental
@@ -15,7 +15,7 @@
1515--
1616-----------------------------------------------------------------------------
1717
18−module Utils
18+module LAoP.Utils
1919 ( -- | Utility module that provides the 'Natural' data type.
2020 -- The semantic associated with this data type is that
2121 -- it's meant to be a restricted 'Int' value. For example
@@ -94,7 +94,10 @@ module Utils
9494 coerceNat,
9595 coerceNat2,
9696 coerceNat3,
97+
98+ -- * Powerset data type
99+ Powerset (..)
97100 )
98101where
99102
100−import Utils.Internal
103+import LAoP.Utils.Internal
src/Utils/Internal.hs → src/LAoP/Utils/Internal.hsrenamed+64−2
@@ -5,7 +5,7 @@
55{-# LANGUAGE KindSignatures #-}
66{-# LANGUAGE ScopedTypeVariables #-}
77
8−module Utils.Internal
8+module LAoP.Utils.Internal
99 ( -- | This is an internal module and it is not meant to be imported.
1010 --
1111 -- Utility module that provides the 'Natural' data type.
@@ -78,7 +78,7 @@ module Utils.Internal
7878 -- @
7979 --
8080 -- * 'Natural' data type
81− Natural,
81+ Natural(..),
8282 nat,
8383
8484 -- * Coerce auxiliar functions to help promote 'Int' typed functions to
@@ -86,11 +86,16 @@ module Utils.Internal
8686 coerceNat,
8787 coerceNat2,
8888 coerceNat3,
89+
90+ -- * Powerset data type
91+ Powerset (..)
8992 )
9093where
9194
9295import Data.Coerce
9396import Data.Proxy
97+import Data.List
98+import Data.Maybe
9499import GHC.TypeLits
95100import Control.DeepSeq
96101
@@ -174,3 +179,60 @@ instance
174179 fstI = fromEnum a
175180 sndI = fromEnum b
176181 in fstI * lengthB + sndI
182+
183+instance
184+ ( Bounded a,
185+ Bounded b
186+ ) => Bounded (Either a b)
187+ where
188+ minBound = Left (minBound :: a)
189+ maxBound = Right (maxBound :: b)
190+
191+instance
192+ ( Enum a,
193+ Bounded a,
194+ Enum b,
195+ Bounded b
196+ ) => Enum (Either a b)
197+ where
198+ toEnum i =
199+ let la = fmap Left ([minBound..maxBound] :: [a])
200+ lb = fmap Right ([minBound..maxBound] :: [b])
201+ in (la ++ lb) !! i
202+
203+ fromEnum (Left a) = fromEnum a
204+ fromEnum (Right b) = fromEnum (maxBound :: a) + fromEnum b + 1
205+
206+-- | Powerset data type.
207+--
208+-- This data type is a newtype wrapper around '[]'. This exists in order to
209+-- implement an 'Enum' and 'Bounded' instance that cannot be harmful for the outside.
210+newtype Powerset a = PS [a]
211+ deriving (Eq, Show, Read)
212+
213+powerset :: [a] -> [[a]]
214+powerset [] = [[]]
215+powerset (x:xs) = powerset xs ++ [x:ps | ps <- powerset xs]
216+
217+instance
218+ ( Enum a,
219+ Bounded a
220+ ) => Bounded (Powerset a)
221+ where
222+ minBound = PS []
223+ maxBound = PS [minBound .. maxBound]
224+
225+instance
226+ ( Bounded a,
227+ Enum a,
228+ Eq a
229+ ) => Enum (Powerset a)
230+ where
231+ toEnum i =
232+ let as = [minBound .. maxBound]
233+ in PS (powerset as !! i)
234+
235+ fromEnum (PS []) = 0
236+ fromEnum (PS x) =
237+ let as = [minBound .. maxBound]
238+ in fromMaybe (error "Does not exist") $ elemIndex x (powerset as)
src/Relation/Internal.hsdeleted−159
@@ -1,159 +0,0 @@
1−{-# LANGUAGE GADTs #-}
2−{-# LANGUAGE UndecidableInstances #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE ScopedTypeVariables #-}
5−{-# LANGUAGE StandaloneDeriving #-}
6−{-# LANGUAGE DerivingVia #-}
7−{-# LANGUAGE DataKinds #-}
8−
9−-----------------------------------------------------------------------------
10−-- |
11−-- Module : Relation.Internal
12−-- Copyright : (c) Armando Santos 2019-2020
13−-- Maintainer : armandoifsantos@gmail.com
14−-- Stability : experimental
15−--
16−-- The AoP discipline generalises functions to relations which are
17−-- Boolean matrices.
18−--
19−-- This module offers many of the combinators of the Algebra of
20−-- Programming discipline. It is still under construction and very
21−-- experimental.
22−--
23−-- This is an Internal module and it is no supposed to be imported.
24−--
25−-----------------------------------------------------------------------------
26−
27−module Relation.Internal
28− (
29− )
30− where
31−
32−import Data.Void
33−import qualified Matrix.Internal as I
34−import Utils
35−import Control.DeepSeq
36−import qualified Control.Category as C
37−import Data.Coerce
38−import GHC.TypeLits
39−
40−type Boolean = Natural 0 1
41−newtype Relation a b = R (I.Matrix Boolean (I.Normalize a) (I.Normalize b))
42− deriving (Show, Eq, Ord, NFData) via (I.Matrix (Natural 1 1) (I.Normalize a) (I.Normalize b))
43−
44−deriving instance (Read (I.Matrix Boolean (I.Normalize a) (I.Normalize b))) => Read (Relation a b)
45−
46−instance C.Category Relation where
47− id = undefined
48− (.) = comp
49−
50−instance Num (Relation a b) where
51− (R a) + (R b) = R (I.orM a b)
52−
53− (R a) - (R b) = R (I.subM a b)
54−
55− (R a) * (R b) = R (I.andM a b)
56−
57−-- Type alias
58−type Zero = Void
59−type One = ()
60−
61−-- Primitives
62−
63−empty :: Relation Zero Zero
64−empty = R I.Empty
65−
66−one :: Boolean -> Relation One One
67−one = R . I.One
68−
69−junc :: (I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b))
70− => Relation a c -> Relation b c -> Relation (Either a b) c
71−junc (R a) (R b) = R (I.Junc a b)
72−
73−split :: (I.Normalize (Either a b) ~ Either (I.Normalize a) (I.Normalize b))
74− => Relation c a -> Relation c b -> Relation c (Either a b)
75−split (R a) (R b) = R (I.Split a b)
76−
77−-- Construction
78−
79−fromLists :: (I.FromLists Boolean (I.Normalize a) (I.Normalize b)) => [[Boolean]] -> Relation a b
80−fromLists = R . I.fromLists
81−
82−identity :: (KnownNat (I.Count (I.Normalize a)),I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a
83−identity = R I.identity
84−
85−fromF ::
86− ( Bounded a,
87− Bounded b,
88− Enum a,
89− Enum b,
90− Eq b,
91− KnownNat (I.Count (I.Normalize c)),
92− KnownNat (I.Count (I.Normalize d)),
93− I.FromLists Boolean (I.Normalize d) (I.Normalize c)
94− )
95− => (a -> b) -> Relation c d
96−fromF f = R (I.fromFRel f)
97−
98−fromF' ::
99− ( Bounded b,
100− Bounded a,
101− Enum a,
102− Enum b,
103− Eq b,
104− KnownNat (I.Count (I.Normalize a)),
105− KnownNat (I.Count (I.Normalize b)),
106− I.FromLists Boolean (I.Normalize b) (I.Normalize a)
107− )
108− => (a -> b) -> Relation a b
109−fromF' f = R (I.fromFRel' f)
110−
111−-- | Relational composition
112−comp :: forall a b c . Relation b c -> Relation a b -> Relation a c
113−comp (R a) (R b) = R (I.compRel a b)
114−
115−-- | Relational converse
116−conv :: Relation a b -> Relation b a
117−conv (R a) = R (I.tr a)
118−
119−-- | Relational inclusion (subset or equal)
120−sse :: Relation a b -> Relation a b -> Bool
121−sse a b = a <= b
122−
123−-- | Relational intersection
124−--
125−-- @M `inter` N = M * N@
126−intersection :: Relation a b -> Relation a b -> Relation a b
127−intersection a b = a * b
128−
129−-- | Relational union
130−--
131−-- @M `union` N = M + N - M * N
132−union :: Relation a b -> Relation a b -> Relation a b
133−union a b = a + b - a * b
134−
135−-- | Relation Kernel
136−ker :: Relation a b -> Relation a a
137−ker r = conv r `comp` r
138−
139−-- | Relation Image
140−img :: Relation a b -> Relation b b
141−img r = r `comp` conv r
142−
143−-- | Properties of relations
144−coreflexive :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a a -> Bool
145−coreflexive r = r <= identity
146−
147−simple :: (KnownNat (I.Count (I.Normalize b)), I.FromLists Boolean (I.Normalize b) (I.Normalize b)) => Relation a b -> Bool
148−simple = coreflexive . img
149−
150−injective :: (KnownNat (I.Count (I.Normalize a)), I.FromLists Boolean (I.Normalize a) (I.Normalize a)) => Relation a b -> Bool
151−injective = simple . conv
152−
153−-- | Relation pretty printing
154−pretty :: (KnownNat (I.Count (I.Normalize a))) => Relation a b -> String
155−pretty (R a) = I.pretty a
156−
157−-- | Relation pretty printing
158−prettyPrint :: (KnownNat (I.Count (I.Normalize a))) => Relation a b -> IO ()
159−prettyPrint (R a) = I.prettyPrint a