packages feed

equivalence 0.1.1 → 0.2.0

raw patch · 3 files changed

+334/−89 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Equivalence.Monad: instance (Monad m, Ord v) => MonadEquiv c v (EquivT s c v m)
- Data.Equivalence.Monad: instance (MonadEquiv c v m) => MonadEquiv c v (ReaderT r m)
- Data.Equivalence.Monad: instance (MonadEquiv c v m) => MonadEquiv c v (StateT s m)
- Data.Equivalence.Monad: instance (MonadEquiv c v m, Error e) => MonadEquiv c v (ErrorT e m)
- Data.Equivalence.Monad: instance (MonadEquiv c v m, Monoid w) => MonadEquiv c v (WriterT w m)
- Data.Equivalence.STT: instance Eq (Entry s c a)
+ Data.Equivalence.Monad: (===) :: (MonadEquiv c v d m) => c -> c -> m Bool
+ Data.Equivalence.Monad: combine :: (MonadEquiv c v d m) => c -> c -> m c
+ Data.Equivalence.Monad: combineAll :: (MonadEquiv c v d m) => [c] -> m ()
+ Data.Equivalence.Monad: desc :: (MonadEquiv c v d m) => c -> m d
+ Data.Equivalence.Monad: equateAll :: (MonadEquiv c v d m) => [v] -> m ()
+ Data.Equivalence.Monad: getClass :: (MonadEquiv c v d m) => v -> m c
+ Data.Equivalence.Monad: instance (Monad m, Ord v) => MonadEquiv (Class s d v) v d (EquivT s d v m)
+ Data.Equivalence.Monad: instance (MonadEquiv c v d m) => MonadEquiv c v d (ReaderT r m)
+ Data.Equivalence.Monad: instance (MonadEquiv c v d m) => MonadEquiv c v d (StateT s m)
+ Data.Equivalence.Monad: instance (MonadEquiv c v d m, Error e) => MonadEquiv c v d (ErrorT e m)
+ Data.Equivalence.Monad: instance (MonadEquiv c v d m, Monoid w) => MonadEquiv c v d (WriterT w m)
+ Data.Equivalence.Monad: remove :: (MonadEquiv c v d m) => c -> m Bool
+ Data.Equivalence.Monad: removeClass :: (MonadEquiv c v d m) => v -> m Bool
+ Data.Equivalence.STT: combine :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> Class s c a -> STT s m (Class s c a)
+ Data.Equivalence.STT: combineAll :: (Monad m, Ord a) => Equiv s c a -> [Class s c a] -> STT s m ()
+ Data.Equivalence.STT: data Class s c a
+ Data.Equivalence.STT: desc :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> STT s m c
+ Data.Equivalence.STT: equateAll :: (Monad m, Ord a) => Equiv s c a -> [a] -> STT s m ()
+ Data.Equivalence.STT: getClass :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m (Class s c a)
+ Data.Equivalence.STT: remove :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> STT s m Bool
+ Data.Equivalence.STT: removeClass :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m Bool
+ Data.Equivalence.STT: same :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> Class s c a -> STT s m Bool
- Data.Equivalence.Monad: class (Monad m, Ord v) => MonadEquiv c v m | m -> v, m -> c
+ Data.Equivalence.Monad: class (Monad m, Ord v) => MonadEquiv c v d m | m -> v, m -> c, m -> d
- Data.Equivalence.Monad: classDesc :: (MonadEquiv c v m) => v -> m c
+ Data.Equivalence.Monad: classDesc :: (MonadEquiv c v d m) => v -> m d
- Data.Equivalence.Monad: equate :: (MonadEquiv c v m) => v -> v -> m ()
+ Data.Equivalence.Monad: equate :: (MonadEquiv c v d m) => v -> v -> m ()
- Data.Equivalence.Monad: equivalent :: (MonadEquiv c v m) => v -> v -> m Bool
+ Data.Equivalence.Monad: equivalent :: (MonadEquiv c v d m) => v -> v -> m Bool

Files

equivalence.cabal view
@@ -1,5 +1,5 @@ Name:            equivalence-Version:         0.1.1+Version:         0.2.0 License:         BSD3 License-File:    LICENSE Author:          Patrick Bahr <paba@diku.dk>
src/Data/Equivalence/Monad.hs view
@@ -31,7 +31,8 @@      runEquivM      ) where -import Data.Equivalence.STT hiding (equate, equivalent, classDesc)+import Data.Equivalence.STT hiding (equate, equateAll, equivalent, classDesc, removeClass,+                                    getClass , combine, combineAll, same , desc , remove ) import qualified Data.Equivalence.STT  as S   @@ -114,7 +115,7 @@ {-| This class specifies the interface for a monadic computation that maintains an equivalence relation.  -} -class (Monad m, Ord v) => MonadEquiv c v m | m -> v, m -> c where+class (Monad m, Ord v) => MonadEquiv c v d m | m -> v, m -> c, m -> d where     {-| This function decides whether the two given elements are         equivalent in the current equivalence relation -} @@ -122,14 +123,68 @@     {-| This function obtains the descriptor of the given element's         equivalence class. -} -    classDesc :: v -> m c+    classDesc :: v -> m d     +    {-| This function equates the element in the given list. That is, it+      unions the equivalence classes of the elements and combines their+      descriptor. -}++    equateAll :: [v] -> m ()+         {-| This function equates the given two elements. That is it         unions the equivalence classes of the two elements. -}      equate :: v -> v -> m ()+    equate x y = equateAll [x,y] -instance (Monad m, Ord v) => MonadEquiv c v (EquivT s c v m) where+    {-| This function removes the equivalence class of the given+      element. If there is no corresponding equivalence class, @False@ is+      returned; otherwise @True@. -}+    removeClass :: v -> m Bool++                   +    {-| This function provides the equivalence class the given element+      is contained in. -}++    getClass :: v -> m c+                +    +    {-| This function combines all equivalence classes in the given+      list. Afterwards all elements in the argument list represent the same+      equivalence class! -}++    combineAll :: [c] -> m ()++    +    {-| This function combines the two given equivalence+      classes. Afterwards both arguments represent the same equivalence+      class! One of it is returned in order to represent the new combined+      equivalence class. -}++    combine :: c -> c -> m c+    combine x y = combineAll [x,y] >> return x+               +    {-| This function decides whether the two given equivalence classes+      are the same. -}++    (===) :: c -> c -> m Bool++    +    {-| This function returns the descriptor of the given+      equivalence class. -}++    desc :: c -> m d++    {-| This function removes the given equivalence class. If the+      equivalence class does not exists anymore @False@ is returned;+      otherwise @True@. -}++    remove :: c -> m Bool+++                                     ++instance (Monad m, Ord v) => MonadEquiv (Class s d v) v d (EquivT s d v m) where     equivalent x y = EquivT $ do       part <- ask       lift $ S.equivalent part x y@@ -138,26 +193,90 @@       part <- ask       lift $ S.classDesc part x            +    equateAll x = EquivT $ do+      part <- ask+      lift $ S.equateAll part x+                equate x y = EquivT $ do       part <- ask       lift $ S.equate part x y -instance (MonadEquiv c v m, Monoid w) => MonadEquiv c v (WriterT w m) where+    removeClass x = EquivT $ do+      part <- ask+      lift $ S.removeClass part x++    getClass x = EquivT $ do+      part <- ask+      lift $ S.getClass part x++    combineAll x = EquivT $ do+      part <- ask+      lift $ S.combineAll part x++    combine x y = EquivT $ do+      part <- ask+      lift $ S.combine part x y++    x === y = EquivT $ do+      part <- ask+      lift $ S.same part x y++    desc x = EquivT $ do+      part <- ask+      lift $ S.desc part x++    remove x = EquivT $ do+      part <- ask+      lift $ S.remove part x++instance (MonadEquiv c v d m, Monoid w) => MonadEquiv c v d (WriterT w m) where     equivalent x y = lift $ equivalent x y     classDesc = lift . classDesc+    equateAll x = lift $ equateAll x     equate x y = lift $ equate x y+    removeClass x = lift $ removeClass x+    getClass x = lift $ getClass x+    combineAll x = lift $ combineAll x+    combine x y = lift $ combine x y+    x === y = lift $ (===) x y+    desc x = lift $ desc x+    remove x = lift $ remove x -instance (MonadEquiv c v m, Error e) => MonadEquiv c v (ErrorT e m) where+instance (MonadEquiv c v d m, Error e) => MonadEquiv c v d (ErrorT e m) where     equivalent x y = lift $ equivalent x y     classDesc = lift . classDesc+    equateAll x = lift $ equateAll x     equate x y = lift $ equate x y+    removeClass x = lift $ removeClass x+    getClass x = lift $ getClass x+    combineAll x = lift $ combineAll x+    combine x y = lift $ combine x y+    x === y = lift $ (===) x y+    desc x = lift $ desc x+    remove x = lift $ remove x -instance (MonadEquiv c v m) => MonadEquiv c v (StateT s m) where+instance (MonadEquiv c v d m) => MonadEquiv c v d (StateT s m) where     equivalent x y = lift $ equivalent x y     classDesc = lift . classDesc+    equateAll x = lift $ equateAll x     equate x y = lift $ equate x y+    removeClass x = lift $ removeClass x+    getClass x = lift $ getClass x+    combineAll x = lift $ combineAll x+    combine x y = lift $ combine x y+    x === y = lift $ (===) x y+    desc x = lift $ desc x+    remove x = lift $ remove x -instance (MonadEquiv c v m) => MonadEquiv c v (ReaderT r m) where+instance (MonadEquiv c v d m) => MonadEquiv c v d (ReaderT r m) where     equivalent x y = lift $ equivalent x y     classDesc = lift . classDesc+    equateAll x = lift $ equateAll x     equate x y = lift $ equate x y+    removeClass x = lift $ removeClass x+    getClass x = lift $ getClass x+    combineAll x = lift $ combineAll x+    combine x y = lift $ combine x y+    x === y = lift $ (===) x y+    desc x = lift $ desc x+    remove x = lift $ remove x
src/Data/Equivalence/STT.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE MultiParamTypeClasses #-}+ -------------------------------------------------------------------------------- -- | -- Module      : Data.Equivalence.STT@@ -37,26 +39,43 @@ --------------------------------------------------------------------------------  module Data.Equivalence.STT-  ( leastEquiv+  ( +   -- * Equivalence Relation+    Equiv+  , Class+  , leastEquiv+  -- * Operations on Equivalence Classes+  , getClass+  , combine+  , combineAll+  , same+  , desc+  , remove+  -- * Operations on Elements   , equate+  , equateAll   , equivalent   , classDesc-  , Equiv+  , removeClass   ) where  import Control.Monad.ST.Trans import Control.Monad +import Data.Maybe+ import Data.Map (Map) import qualified Data.Map as Map +newtype Class s c a = Class (Entry s c a)++ {-| This type represents a reference to an entry in the tree data structure. An entry of type 'Entry' @s c a@ lives in the state space indexed by @s@, contains equivalence class descriptors of type @c@ and has elements of type @a@.-}  newtype Entry s c a = Entry (STRef s (EntryData s c a))-    deriving (Eq)  {-| This type represents entries (nodes) in the tree data structure. Entry data of type 'EntryData' @s c a@ lives in the state space@@ -70,9 +89,12 @@                      | Root {       entryDesc :: c,       entryWeight :: Int,-      entryValue :: a+      entryValue :: a,+      entryDeleted :: Bool     } +type Entries s c a = STRef s (Map a (Entry s c a))+ {-| This is the top-level data structure that represents an equivalence relation. An equivalence relation of type 'Equiv' @s c a@ lives in the state space indexed by @s@, contains equivalence class@@ -80,25 +102,14 @@  data Equiv s c a = Equiv {       -- | maps elements to their entry in the tree data structure-      entries :: STRef s (Map a (Entry s c a)), +      entries :: Entries s c a,        -- | constructs an equivalence class descriptor for a singleton class       singleDesc :: a -> c,       -- | combines the equivalence class descriptor of two classes       --   which are meant to be combined.       combDesc :: c -> c -> c       }-{--   not used -{-|-  This function modifies the content of a reference cell.--}--modifySTRef :: (Monad m) => STRef s a -> (a -> a) -> STT s m ()-modifySTRef r f = readSTRef r >>= (writeSTRef r . f)---}- {-| This function constructs the initial data structure for maintaining an equivalence relation. That is it represents, the fines (or least) equivalence class (of the set of all elements of type@@ -122,50 +133,89 @@  This function performs path compression.  -} -representative' :: Monad m => Entry s c a -> STT s m (Maybe (Entry s c a))+representative' :: Monad m => Entry s c a -> STT s m (Maybe (Entry s c a),Bool) representative' (Entry e) = do   ed <- readSTRef e   case ed of-    Root {} -> return Nothing-    Node { entryParent = parent} -> do-      mparent' <- representative' parent+    Root {entryDeleted = del} -> do+      return (Nothing, del)+    Node {entryParent = parent} -> do+      (mparent',del) <- representative' parent       case mparent' of-        Nothing -> return $ Just parent-        Just parent' -> writeSTRef e ed{entryParent = parent'} >> return (Just parent')--+        Nothing -> return $ (Just parent, del)+        Just parent' -> writeSTRef e ed{entryParent = parent'} >> return (Just parent', del)   {-| This function returns the representative entry of the argument's equivalence class (i.e. the root of its tree).  This function performs path compression.  -}-representative :: Monad m => Entry s c a -> STT s m (Entry s c a)-representative entry = do-  mrepr <- representative' entry-  case mrepr of-    Nothing -> return entry-    Just repr -> return repr +representative :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m (Entry s c a)+representative eq v = do+  mentry <- getEntry eq v+  case mentry of -- check whether there is an entry+    Nothing -> mkEntry eq v -- if not, create a new one+    Just entry -> do+      (mrepr,del) <- representative' entry+      if del -- check whether equivalence class was deleted+        then mkEntry eq v -- if so, create a new entry+        else case mrepr of+               Nothing -> return entry+               Just repr -> return repr -{-| This function looks up the entry of the given element in the given-equivalence relation representation. If there is none yet, then a-fresh one is constructed which then represents a new singleton-equivalence class! -}+{-| This function provides the representative entry of the given+equivalence class. This function performs path compression. -} -getEntry' :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m (Entry s c a)-getEntry' Equiv {entries = mref, singleDesc = mkDesc} val = do+classRep :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> STT s m (Entry s c a)+classRep eq (Class entry) = do+  (mrepr,del) <- representative' entry+  if del -- check whether equivalence class was deleted+    then mkEntry' eq entry -- if so, create a new entry+    else case mrepr of+           Nothing -> return entry+           Just repr -> return repr+  ++{-| This function constructs a new (root) entry containing the given+entry's value, inserts it into the lookup table (thereby removing any+existing entry). -}++mkEntry' :: (Monad m, Ord a)+        => Equiv s c a -> Entry s c a+        -> STT s m (Entry s c a)  -- ^ the constructed entry+mkEntry' eq (Entry e) = readSTRef e >>= mkEntry eq . entryValue++{-| This function constructs a new (root) entry containing the given+value, inserts it into the lookup table (thereby removing any existing+entry). -}++mkEntry :: (Monad m, Ord a)+        => Equiv s c a -> a+        -> STT s m (Entry s c a)  -- ^ the constructed entry+mkEntry Equiv {entries = mref, singleDesc = mkDesc} val = do+  e <- newSTRef Root+       { entryDesc = mkDesc val,+         entryWeight = 1,+         entryValue = val,+         entryDeleted = False+       }+  let entry = Entry e   m <- readSTRef mref-  case Map.lookup val m of-    Nothing -> do-      e <- newSTRef Root-            { entryDesc = mkDesc val,-              entryWeight = 1,-              entryValue = val-            }-      let entry = Entry e-      writeSTRef mref (Map.insert val entry m)-      return entry+  writeSTRef mref (Map.insert val entry m)+  return entry++{-| This function provides the equivalence class the given element is+contained in. -}++getClass :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m (Class s c a)+getClass eq v = liftM Class (getEntry' eq v)++getEntry' :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m (Entry s c a)+getEntry' eq v = do+  mentry <- getEntry eq v+  case mentry of+    Nothing -> mkEntry eq v     Just entry -> return entry  {-| This function looks up the entry of the given element in the given@@ -179,24 +229,14 @@     Nothing -> return Nothing     Just entry -> return $ Just entry ++ {-| This function equates the two given elements. That is, it unions the equivalence classes of the two elements and combines their descriptor. -} -equate :: (Monad m, Ord a) => Equiv s c a -> a -> a -> STT s m ()-equate equiv x y = do-  ex <- getEntry' equiv x-  ey <- getEntry' equiv  y-  equate' equiv ex ey---{-| This function equates the two given entries. That is, it performs-a weighted union of their trees combines their descriptor. -}--equate' :: (Monad m, Ord a) => Equiv s c a -> Entry s c a -> Entry s c a -> STT s m ()-equate' Equiv {combDesc = mkDesc} x y = do-  repx@(Entry rx) <- representative x-  repy@(Entry ry) <- representative y+equateEntry :: (Monad m, Ord a) => Equiv s c a -> Entry s c a -> Entry s c a -> STT s m ()+equateEntry Equiv {combDesc = mkDesc} repx@(Entry rx) repy@(Entry ry) =    when (rx /= ry) $ do     dx@Root{entryWeight = wx, entryDesc = chx, entryValue = vx} <- readSTRef rx     dy@Root{entryWeight = wy, entryDesc = chy, entryValue = vy} <- readSTRef ry@@ -208,39 +248,125 @@        writeSTRef rx Node {entryParent = repy, entryValue = vx}        writeSTRef ry dy{entryWeight = wx + wy, entryDesc = mkDesc chx chy} +{-| This function equates all elements given in the list by pairwise+applying 'equateEntry'. -}++equateEntries :: (Monad m, Ord a) => Equiv s c a -> [Entry s c a] -> STT s m ()+equateEntries eq es = run es+    where run (e:r@(f:_)) = equateEntry eq e f >> run r+          run _ = return ()++++{-| This function combines all equivalence classes in the given+list. Afterwards all elements in the argument list represent the same+equivalence class! -}++combineAll :: (Monad m, Ord a) => Equiv s c a -> [Class s c a] -> STT s m ()+combineAll eq cs = mapM (classRep eq) cs >>= equateEntries eq+++{-| This function combines the two given equivalence+classes. Afterwards both arguments represent the same equivalence+class! One of it is returned in order to represent the new combined+equivalence class. -}++combine :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> Class s c a -> STT s m (Class s c a)+combine eq x y = combineAll eq [x,y] >> return x+++{-| This function equates the element in the given list. That is, it+unions the equivalence classes of the elements and combines their+descriptor. -}++equateAll :: (Monad m, Ord a) => Equiv s c a -> [a] -> STT s m ()+equateAll eq els = mapM (representative eq) els >>= equateEntries eq++{-| This function equates the two given elements. That is, it unions+the equivalence classes of the two elements and combines their+descriptor. -}++equate :: (Monad m, Ord a) => Equiv s c a -> a -> a -> STT s m ()+equate eq x y = equateAll eq [x,y]+++{-| This function returns the descriptor of the given+equivalence class. -}++desc :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> STT s m c+desc eq cl = do+  Entry e <- classRep eq cl+  liftM entryDesc $ readSTRef e+ {-| This function returns the descriptor of the given element's equivalence class. -}  classDesc :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m c classDesc eq val = do-  mentry <- getEntry eq val-  case mentry of-    Nothing -> return $ singleDesc eq val-    Just entry -> classDesc' entry+  Entry e <- representative eq val+  liftM entryDesc $ readSTRef e -{-| This function returns the descriptor of the given entry's tree. -} -classDesc' :: (Monad m) => Entry s c a -> STT s m c-classDesc' entry = do-  Entry e <- representative entry-  liftM entryDesc $ readSTRef e+{-| This function decides whether the two given equivalence classes+are the same. -} +same :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> Class s c a -> STT s m Bool+same eq c1 c2 = do+  (Entry r1) <- classRep eq c1+  (Entry r2) <- classRep eq c2+  return (r1 == r2)+ {-| This function decides whether the two given elements are in the same equivalence class according to the given equivalence relation representation. -}  equivalent :: (Monad m, Ord a) => Equiv s c a -> a -> a -> STT s m Bool equivalent eq v1 v2 = do-  me1 <- getEntry eq v1-  me2 <- getEntry eq v2-  case (me1,me2) of-    (Just e1, Just e2) -> equivalent' e1 e2-    (Nothing, Nothing) -> return $ v1 == v2-    _ -> return False-    -{-| This function decides whether the two given entries are in the-same tree (by comparing their roots).-}+  (Entry r1) <- representative eq v1+  (Entry r2) <- representative eq v2+  return (r1 == r2) -equivalent' :: (Monad m, Ord a) => Entry s c a -> Entry s c a -> STT s m Bool-equivalent' e1 e2 = liftM2 (==) (representative e1) (representative e2) ++{-|+  This function modifies the content of a reference cell.+ -}++modifySTRef :: (Monad m) => STRef s a -> (a -> a) -> STT s m ()+modifySTRef r f = readSTRef r >>= (writeSTRef r . f)+++{-| This function marks the given root entry as deleted.  -}++removeEntry :: (Monad m, Ord a) => Entry s c a -> STT s m ()+removeEntry (Entry r) = modifySTRef r change+    where change e = e {entryDeleted = True}+++{-| This function removes the given equivalence class. If the+equivalence class does not exists anymore @False@ is returned;+otherwise @True@. -}++remove :: (Monad m, Ord a) => Equiv s c a -> Class s c a -> STT s m Bool+remove _ (Class entry) = do+  (mentry, del) <- representative' entry+  if del +    then return False+    else removeEntry (fromMaybe entry mentry)+         >> return True++{-| This function removes the equivalence class of the given+element. If there is no corresponding equivalence class, @False@ is+returned; otherwise @True@. -}++removeClass :: (Monad m, Ord a) => Equiv s c a -> a -> STT s m Bool+removeClass eq v = do+  mentry <- getEntry eq v+  case mentry of+    Nothing -> return False+    Just entry -> do+      (mentry, del) <- representative' entry+      if del +        then return False+        else removeEntry (fromMaybe entry mentry)+             >> return True