subhask-0.1.0.0: src/SubHask/Category/Finite.hs
-- {-# LANGUAGE ScopedTypeVariables #-}
{- |
Finite categories are categories with a finite number of arrows.
In our case, this corresponds to functions with finite domains (and hence, ranges).
These functions have a number of possible representations.
Which is best will depend on the given function.
One common property is that these functions support decidable equality.
-}
module SubHask.Category.Finite
(
-- * Function representations
-- ** Sparse permutations
SparseFunction
, proveSparseFunction
, list2sparseFunction
-- ** Sparse monoids
, SparseFunctionMonoid
-- ** Dense functions
, DenseFunction
, proveDenseFunction
-- * Finite types
, FiniteType (..)
, ZIndex
)
where
import Control.Monad
import GHC.Prim
import GHC.TypeLits
import Data.Proxy
import qualified Data.Map as Map
import qualified Data.Vector.Unboxed as VU
import qualified Prelude as P
import SubHask.Algebra
import SubHask.Algebra.Group
import SubHask.Category
import SubHask.Internal.Prelude
import SubHask.SubType
import SubHask.TemplateHaskell.Deriving
-------------------------------------------------------------------------------
-- | A type is finite if there is a bijection between it and the natural numbers.
-- The 'index'/'deZIndex' functions implement this bijection.
class KnownNat (Order a) => FiniteType a where
type Order a :: Nat
index :: a -> ZIndex a
deZIndex :: ZIndex a -> a
enumerate :: [a]
getOrder :: a -> Integer
instance KnownNat n => FiniteType (Z n) where
type Order (Z n) = n
index i = ZIndex i
deZIndex (ZIndex i) = i
enumerate = [ mkQuotient i | i <- [0..n - 1] ]
where
n = natVal (Proxy :: Proxy n)
getOrder z = natVal (Proxy :: Proxy n)
-- | The 'ZIndex' class is a newtype wrapper around the natural numbers 'Z'.
--
-- FIXME: remove this layer; I don't think it helps
--
newtype ZIndex a = ZIndex (Z (Order a))
deriveHierarchy ''ZIndex [ ''Eq_, ''P.Ord ]
-- | Swap the phantom type between two indices.
swapZIndex :: Order a ~ Order b => ZIndex a -> ZIndex b
swapZIndex (ZIndex i) = ZIndex i
-------------------------------------------------------------------------------
-- | Represents finite functions as a map associating input/output pairs.
data SparseFunction a b where
SparseFunction ::
( FiniteType a
, FiniteType b
, Order a ~ Order b
) => Map.Map (ZIndex a) (ZIndex b) -> SparseFunction a b
instance Category SparseFunction where
type ValidCategory SparseFunction a =
( FiniteType a
)
id = SparseFunction $ Map.empty
(SparseFunction f1).(SparseFunction f2) = SparseFunction
(Map.map (\a -> find a f1) f2)
where
find k map = case Map.lookup k map of
Just v -> v
Nothing -> swapZIndex k
-- instance Sup SparseFunction (->) (->)
-- instance Sup (->) SparseFunction (->)
-- instance SparseFunction <: (->) where
-- embedType_ = Embed2 $ map2function f
-- where
-- map2function map k = case Map.lookup (index k) map of
-- Just v -> deZIndex v
-- Nothing -> deZIndex $ swapZIndex $ index k
-- | Generates a sparse representation of a 'Hask' function.
-- This proof will always succeed, although it may be computationally expensive if the 'Order' of a and b is large.
proveSparseFunction ::
( ValidCategory SparseFunction a
, ValidCategory SparseFunction b
, Order a ~ Order b
) => (a -> b) -> SparseFunction a b
proveSparseFunction f = SparseFunction
$ Map.fromList
$ P.map (\a -> (index a,index $ f a)) enumerate
-- | Generate sparse functions on some subset of the domain.
list2sparseFunction ::
( ValidCategory SparseFunction a
, ValidCategory SparseFunction b
, Order a ~ Order b
) => [Z (Order a)] -> SparseFunction a b
list2sparseFunction xs = SparseFunction $ Map.fromList $ go xs
where
go (y:[]) = [(ZIndex y, ZIndex $ P.head xs)]
go (y1:y2:ys) = (ZIndex y1,ZIndex y2):go (y2:ys)
-------------------------------------------------------------------------------
data SparseFunctionMonoid a b where
SparseFunctionMonoid ::
( FiniteType a
, FiniteType b
, Monoid a
, Monoid b
, Order a ~ Order b
) => Map.Map (ZIndex a) (ZIndex b) -> SparseFunctionMonoid a b
instance Category SparseFunctionMonoid where
type ValidCategory SparseFunctionMonoid a =
( FiniteType a
, Monoid a
)
id :: forall a. ValidCategory SparseFunctionMonoid a => SparseFunctionMonoid a a
id = SparseFunctionMonoid $ Map.fromList $ P.zip xs xs
where
xs = P.map index (enumerate :: [a])
(SparseFunctionMonoid f1).(SparseFunctionMonoid f2) = SparseFunctionMonoid
(Map.map (\a -> find a f1) f2)
where
find k map = case Map.lookup k map of
Just v -> v
Nothing -> index zero
-- instance Sup SparseFunctionMonoid (->) (->)
-- instance Sup (->) SparseFunctionMonoid (->)
-- instance (SparseFunctionMonoid <: (->)) where
-- embedType_ = Embed2 $ map2function f
-- where
-- map2function map k = case Map.lookup (index k) map of
-- Just v -> deZIndex v
-- Nothing -> zero
---------------------------------------
{-
instance (FiniteType b, Semigroup b) => Semigroup (SparseFunctionMonoid a b) where
(SparseFunctionMonoid f1)+(SparseFunctionMonoid f2) = SparseFunctionMonoid $ Map.unionWith go f1 f2
where
go b1 b2 = index $ deZIndex b1 + deZIndex b2
instance
( FiniteType a
, FiniteType b
, Monoid a
, Monoid b
, Order a ~ Order b
) => Monoid (SparseFunctionMonoid a b) where
zero = SparseFunctionMonoid $ Map.empty
instance
( FiniteType b
, Abelian b
) => Abelian (SparseFunctionMonoid a b)
instance (FiniteType b, Group b) => Group (SparseFunctionMonoid a b) where
negate (SparseFunctionMonoid f) = SparseFunctionMonoid $ Map.map (index.negate.deZIndex) f
type instance Scalar (SparseFunctionMonoid a b) = Scalar b
instance (FiniteType b, Module b) => Module (SparseFunctionMonoid a b) where
r *. (SparseFunctionMonoid f) = SparseFunctionMonoid $ Map.map (index.(r*.).deZIndex) f
instance (FiniteType b, VectorSpace b) => VectorSpace (SparseFunctionMonoid a b) where
(SparseFunctionMonoid f) ./ r = SparseFunctionMonoid $ Map.map (index.(./r).deZIndex) f
-}
-------------------------------------------------------------------------------
-- | Represents finite functions as a hash table associating input/output value pairs.
data DenseFunction (a :: *) (b :: *) where
DenseFunction ::
( FiniteType a
, FiniteType b
) => VU.Vector Int -> DenseFunction a b
instance Category DenseFunction where
type ValidCategory DenseFunction (a :: *) =
( FiniteType a
)
id :: forall a. ValidCategory DenseFunction a => DenseFunction a a
id = DenseFunction $ VU.generate n id
where
n = fromIntegral $ natVal (Proxy :: Proxy (Order a))
(DenseFunction f).(DenseFunction g) = DenseFunction $ VU.map (f VU.!) g
-- instance SubCategory DenseFunction (->) where
-- embed (DenseFunction f) = \x -> deZIndex $ int2index $ f VU.! (index2int $ index x)
-- | Generates a dense representation of a 'Hask' function.
-- This proof will always succeed; however, if the 'Order' of the finite types
-- are very large, it may take a long time.
-- In that case, a `SparseFunction` is probably the better representation.
proveDenseFunction :: forall a b.
( ValidCategory DenseFunction a
, ValidCategory DenseFunction b
) => (a -> b) -> DenseFunction a b
proveDenseFunction f = DenseFunction $ VU.generate n (index2int . index . f . deZIndex . int2index)
where
n = fromIntegral $ natVal (Proxy :: Proxy (Order a))
---------------------------------------
-- internal functions only
int2index :: Int -> ZIndex a
int2index i = ZIndex $ Mod $ fromIntegral i
index2int :: ZIndex a -> Int
index2int (ZIndex (Mod i)) = fromIntegral i