1
Fork 0
mirror of https://github.com/Jaxan/ons-hs.git synced 2025-04-27 22:57:44 +02:00

Adds fold functions for EquivariantSet

This commit is contained in:
Joshua Moerman 2019-01-03 13:52:35 +01:00
parent bde739d3df
commit db2b00273c
3 changed files with 38 additions and 5 deletions

View file

@ -13,13 +13,11 @@ import Data.Proxy
import Data.Set (Set) import Data.Set (Set)
import qualified Data.Set as Set import qualified Data.Set as Set
import Data.Semigroup (Semigroup) import Prelude hiding (map, product)
import Orbit import Orbit
import Support import Support
-- TODO: think about folds (the monoids should be nominal?)
-- TODO: partition / fromList / ...
-- Given a nominal type, we can construct equivariant sets. These simply use a -- Given a nominal type, we can construct equivariant sets. These simply use a
-- standard set data structure. This works well because orbits are uniquely -- standard set data structure. This works well because orbits are uniquely
@ -76,9 +74,11 @@ empty = EqSet Set.empty
singleOrbit :: Orbit a => a -> EquivariantSet a singleOrbit :: Orbit a => a -> EquivariantSet a
singleOrbit = EqSet . Set.singleton . toOrbit singleOrbit = EqSet . Set.singleton . toOrbit
-- Insert whole orbit of a
insert :: (Orbit a, Ord (Orb a)) => a -> EquivariantSet a -> EquivariantSet a insert :: (Orbit a, Ord (Orb a)) => a -> EquivariantSet a -> EquivariantSet a
insert a = EqSet . Set.insert (toOrbit a) . unEqSet insert a = EqSet . Set.insert (toOrbit a) . unEqSet
-- Deletes whole orbit of a
delete :: (Orbit a, Ord (Orb a)) => a -> EquivariantSet a -> EquivariantSet a delete :: (Orbit a, Ord (Orb a)) => a -> EquivariantSet a -> EquivariantSet a
delete a = EqSet . Set.delete (toOrbit a) . unEqSet delete a = EqSet . Set.delete (toOrbit a) . unEqSet
@ -95,11 +95,16 @@ difference a b = EqSet $ Set.difference (unEqSet a) (unEqSet b)
intersection :: Ord (Orb a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a intersection :: Ord (Orb a) => EquivariantSet a -> EquivariantSet a -> EquivariantSet a
intersection a b = EqSet $ Set.intersection (unEqSet a) (unEqSet b) intersection a b = EqSet $ Set.intersection (unEqSet a) (unEqSet b)
-- This is the meat of the file! Relies on the ordering of Orbit.product -- Cartesian product. This is a non trivial thing and relies on the
-- ordering of Orbit.product.
product :: forall a b. (Orbit a, Orbit b) => EquivariantSet a -> EquivariantSet b -> EquivariantSet (a, b) product :: forall a b. (Orbit a, Orbit b) => EquivariantSet a -> EquivariantSet b -> EquivariantSet (a, b)
product (EqSet sa) (EqSet sb) = EqSet . Set.fromDistinctAscList . concat product (EqSet sa) (EqSet sb) = EqSet . Set.fromDistinctAscList . concat
$ Orbit.product (Proxy @a) (Proxy @b) <$> Set.toAscList sa <*> Set.toAscList sb $ Orbit.product (Proxy @a) (Proxy @b) <$> Set.toAscList sa <*> Set.toAscList sb
-- Cartesian product followed by a function (f should be equivariant)
productWith :: (Orbit a, Orbit b, Orbit c, Ord (Orb c)) => (a -> b -> c) -> EquivariantSet a -> EquivariantSet b -> EquivariantSet c
productWith f as bs = map (uncurry f) $ EquivariantSet.product as bs
-- Filter -- Filter
@ -107,6 +112,11 @@ product (EqSet sa) (EqSet sb) = EqSet . Set.fromDistinctAscList . concat
filter :: Orbit a => (a -> Bool) -> EquivariantSet a -> EquivariantSet a filter :: Orbit a => (a -> Bool) -> EquivariantSet a -> EquivariantSet a
filter f (EqSet s) = EqSet . Set.filter (f . getElementE) $ s filter f (EqSet s) = EqSet . Set.filter (f . getElementE) $ s
-- f should be equivariant
partition :: Orbit a => (a -> Bool) -> EquivariantSet a -> (EquivariantSet a, EquivariantSet a)
partition f (EqSet s) = both EqSet . Set.partition (f . getElementE) $ s
where both f (a, b) = (f a, f b)
-- Map -- Map
@ -115,14 +125,32 @@ filter f (EqSet s) = EqSet . Set.filter (f . getElementE) $ s
map :: (Orbit a, Orbit b, Ord (Orb b)) => (a -> b) -> EquivariantSet a -> EquivariantSet b map :: (Orbit a, Orbit b, Ord (Orb b)) => (a -> b) -> EquivariantSet a -> EquivariantSet b
map f = EqSet . Set.map (omap f) . unEqSet map f = EqSet . Set.map (omap f) . unEqSet
-- f should also preserve order on the orbit types! -- precondition: f quivariant and preserves order on the orbits.
-- This means you should know the representation to use it well -- This means you should know the representation to use it well
mapMonotonic :: (Orbit a, Orbit b) => (a -> b) -> EquivariantSet a -> EquivariantSet b mapMonotonic :: (Orbit a, Orbit b) => (a -> b) -> EquivariantSet a -> EquivariantSet b
mapMonotonic f = EqSet . Set.mapMonotonic (omap f) . unEqSet mapMonotonic f = EqSet . Set.mapMonotonic (omap f) . unEqSet
-- Folds
-- I am not sure about the preconditions for folds
foldr :: Orbit a => (a -> b -> b) -> b -> EquivariantSet a -> b
foldr f b = Set.foldr (f . getElementE) b . unEqSet
foldl :: Orbit a => (b -> a -> b) -> b -> EquivariantSet a -> b
foldl f b = Set.foldl (\b -> f b . getElementE) b . unEqSet
-- Conversion -- Conversion
toList :: Orbit a => EquivariantSet a -> [a] toList :: Orbit a => EquivariantSet a -> [a]
toList = fmap getElementE . Set.toList . unEqSet toList = fmap getElementE . Set.toList . unEqSet
fromList :: (Orbit a, Ord (Orb a)) => [a] -> EquivariantSet a
fromList = EqSet . Set.fromList . fmap toOrbit
toOrbitList :: EquivariantSet a -> [Orb a]
toOrbitList = Set.toList . unEqSet
fromOrbitList :: Ord (Orb a) => [Orb a] -> EquivariantSet a
fromOrbitList = EqSet . Set.fromList

View file

@ -48,6 +48,7 @@ instance Orbit Support where
index _ n = n index _ n = n
-- Some instances we can derive via generics
deriving instance (Orbit a, Orbit b) => Orbit (Either a b) deriving instance (Orbit a, Orbit b) => Orbit (Either a b)
deriving instance Orbit () deriving instance Orbit ()

View file

@ -34,6 +34,8 @@ class Orbit a where
getElement :: Orb a -> Support -> a getElement :: Orb a -> Support -> a
index :: Proxy a -> Orb a -> Int index :: Proxy a -> Orb a -> Int
-- We provide default implementations for generic types
-- This enables us to derive Orbit instances by the Haskell compiler
-- default Orb a :: (Generic a, GOrbit (Rep a)) => * -- default Orb a :: (Generic a, GOrbit (Rep a)) => *
type Orb a = GOrb (Rep a) type Orb a = GOrb (Rep a)
@ -137,6 +139,8 @@ selectOrd f x ~(ls, rs) = case f x of
instance Orbit a => GOrbit (K1 c a) where instance Orbit a => GOrbit (K1 c a) where
-- Cannot use (Orb a) here, that may lead to a recursive type
-- So we use the type OrbRec a instead (which uses Orb a one step later).
type GOrb (K1 c a) = OrbRec a type GOrb (K1 c a) = OrbRec a
gtoOrbit (K1 x) = OrbRec (toOrbit x) gtoOrbit (K1 x) = OrbRec (toOrbit x)
gsupport (K1 x) = support x gsupport (K1 x) = support x