module Enumerate.Function.Invert where
import Enumerate.Types
import Enumerate.Function.Types
import Enumerate.Function.Reify
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NonEmpty
import Data.Semigroup ((<>))
import qualified Data.Map as Map
import Data.Map (Map)
import qualified Data.Set as Set
import Data.Set (Set)
import Data.Maybe (fromJust, mapMaybe, listToMaybe)
fromFunction :: (Enumerable a, Ord a) => (a -> b) -> Map a b
fromFunction f = fromFunctionM (return.f)
fromFunctionM :: (Enumerable a, Ord a) => (Partial a b) -> Map a b
fromFunctionM f = Map.fromList (reifyFunctionM f)
isMapTotal :: (Enumerable a, Ord a) => Map a b -> Bool
isMapTotal m = all (\x -> Map.member x m) enumerated
invertMap :: (Ord a, Ord b) => Map a b -> Map b (NonEmpty a)
invertMap m = Map.fromListWith (<>) [(b, a:|[]) | (a, b) <- Map.toList m]
domainM :: (Enumerable a) => (Partial a b) -> [a]
domainM f = foldMap go enumerated
where
go a = case f a of
Nothing -> []
Just{} -> [a]
corange :: (Enumerable a) => (a -> b) -> [a]
corange _ = enumerated
corangeM :: (Enumerable a) => (Partial a b) -> [a]
corangeM _ = enumerated
image :: (Enumerable a) => (a -> b) -> [b]
image f = map f enumerated
imageM :: (Enumerable a) => (Partial a b) -> [b]
imageM f = mapMaybe f enumerated
codomain :: (Enumerable b) => (a -> b) -> [b]
codomain _ = enumerated
codomainM :: (Enumerable b) => (Partial a b) -> [b]
codomainM _ = enumerated
invert :: (Enumerable a, Ord a, Ord b) => (a -> b) -> (b -> [a])
invert f = invertM (return.f)
invertM :: (Enumerable a, Ord a, Ord b) => (Partial a b) -> (b -> [a])
invertM f = g
where
g b = maybe [] NonEmpty.toList (Map.lookup b m)
m = invertMap (fromFunctionM f)
getJectivityM :: (Enumerable a, Enumerable b, Ord a, Ord b) => (Partial a b) -> Maybe Jectivity
getJectivityM f
= case isBijectiveM f of
Just{} -> Just Bijective
Nothing -> case isInjectiveM f of
Just{} -> Just Injective
Nothing -> case isSurjectiveM f of
Just{} -> Just Surjective
Nothing -> Nothing
isInjective :: (Enumerable a, Ord a, Ord b) => (a -> b) -> Maybe (b -> Maybe a)
isInjective f = isInjectiveM (return.f)
isInjectiveM :: (Enumerable a, Ord a, Ord b) => (Partial a b) -> Maybe (b -> Maybe a)
isInjectiveM f = do
_bs <- isUnique (imageM f)
return g
where
g = listToMaybe . invertM f
isUnique :: (Ord a) => [a] -> Maybe (Set a)
isUnique l = if length l == length s then Nothing else Just s
where
s = Set.fromList l
isSurjective :: (Enumerable a, Enumerable b, Ord a, Ord b) => (a -> b) -> Maybe (b -> NonEmpty a)
isSurjective f = isSurjectiveM (return.f)
isSurjectiveM :: (Enumerable a, Enumerable b, Ord a, Ord b) => (Partial a b) -> Maybe (b -> NonEmpty a)
isSurjectiveM f =
if (Set.fromList (codomainM f)) `Set.isSubsetOf` (Set.fromList (imageM f))
then Just g
else Nothing
where
g = NonEmpty.fromList . invertM f
isBijective :: (Enumerable a, Enumerable b, Ord a, Ord b) => (a -> b) -> Maybe (b -> a)
isBijective f = isBijectiveM (return.f)
isBijectiveM :: (Enumerable a, Enumerable b, Ord a, Ord b) => (Partial a b) -> Maybe (b -> a)
isBijectiveM f = do
fIn <- isInjectiveM f
_fSur <- isSurjectiveM f
let fBi = (fromJust . fIn)
return fBi