dawg 0.3.0 → 0.4.0
raw patch · 4 files changed
+87/−93 lines, 4 filesdep −monad-codecPVP ok
version bump matches the API change (PVP)
Dependencies removed: monad-codec
API changes (from Hackage documentation)
- Data.DAWG.Graph: Node :: !a -> !(VMap Id) -> Node a
- Data.DAWG.Graph: value :: Node a -> !a
- Data.DAWG.Wrapper: DAWG :: !(DAWG Int) -> !(AtomCodec a) -> DAWG a
- Data.DAWG.Wrapper: codec :: DAWG a -> !(AtomCodec a)
- Data.DAWG.Wrapper: data DAWG a
- Data.DAWG.Wrapper: dawg :: DAWG a -> !(DAWG Int)
- Data.DAWG.Wrapper: delete :: Ord a => String -> DAWG a -> DAWG a
- Data.DAWG.Wrapper: empty :: DAWG a
- Data.DAWG.Wrapper: fromLang :: [String] -> DAWG ()
- Data.DAWG.Wrapper: fromList :: Ord a => [(String, a)] -> DAWG a
- Data.DAWG.Wrapper: insert :: Ord a => String -> a -> DAWG a -> DAWG a
- Data.DAWG.Wrapper: lookup :: Ord a => String -> DAWG a -> Maybe a
- Data.DAWG.Wrapper: numStates :: DAWG a -> Int
+ Data.DAWG: fromListWith :: Ord a => (a -> a -> a) -> [(String, a)] -> DAWG a
+ Data.DAWG: insertWith :: Ord a => (a -> a -> a) -> String -> a -> DAWG a -> DAWG a
+ Data.DAWG.Graph: Branch :: {-# UNPACK #-} !Id -> !(VMap Id) -> Node a
+ Data.DAWG.Graph: Value :: !a -> Node a
+ Data.DAWG.Graph: eps :: Node a -> {-# UNPACK #-} !Id
+ Data.DAWG.Graph: unValue :: Node a -> !a
Files
- Data/DAWG.hs +62/−14
- Data/DAWG/Graph.hs +23/−9
- Data/DAWG/Wrapper.hs +0/−62
- dawg.cabal +2/−8
Data/DAWG.hs view
@@ -8,9 +8,11 @@ , empty , numStates , insert+, insertWith , delete , lookup , fromList+, fromListWith , fromLang ) where @@ -30,10 +32,10 @@ mkState f g = ((), f g) -- | Leaf node with no children and 'Nothing' value.-leaf :: Node (Maybe a)-leaf = G.Node- { G.value = Nothing- , G.edges = V.empty }+insertLeaf :: Ord a => GraphM a Id +insertLeaf = do+ i <- insertNode (G.Value Nothing)+ insertNode (G.Branch i V.empty) -- | Return node with the given identifier. nodeBy :: Id -> GraphM a (Node (Maybe a))@@ -47,25 +49,45 @@ deleteNode :: Ord a => Node (Maybe a) -> GraphM a () deleteNode = S.state . mkState . G.delete +-- | Invariant: the identifier points to the 'Branch' node. insertM :: Ord a => String -> a -> Id -> GraphM a Id-insertM [] y i = do- n <- nodeBy i- deleteNode n- insertNode (n { G.value = Just y }) insertM (x:xs) y i = do n <- nodeBy i j <- case G.onChar x n of Just j -> return j- Nothing -> insertNode leaf+ Nothing -> insertLeaf k <- insertM xs y j deleteNode n insertNode (G.subst x k n)+insertM [] y i = do+ n <- nodeBy i+ w <- nodeBy (G.eps n)+ deleteNode w+ deleteNode n+ j <- insertNode (G.Value $ Just y)+ insertNode (n { G.eps = j }) -deleteM :: Ord a => String -> Id -> GraphM a Id-deleteM [] i = do+insertWithM :: Ord a => (a -> a -> a) -> String -> a -> Id -> GraphM a Id+insertWithM f (x:xs) y i = do n <- nodeBy i+ j <- case G.onChar x n of+ Just j -> return j+ Nothing -> insertLeaf+ k <- insertWithM f xs y j deleteNode n- insertNode (n { G.value = Nothing })+ insertNode (G.subst x k n)+insertWithM f [] y i = do+ n <- nodeBy i+ w <- nodeBy (G.eps n)+ deleteNode w+ deleteNode n+ let y'new = case G.unValue w of+ Just y' -> f y y'+ Nothing -> y+ j <- insertNode (G.Value $ Just y'new)+ insertNode (n { G.eps = j })++deleteM :: Ord a => String -> Id -> GraphM a Id deleteM (x:xs) i = do n <- nodeBy i case G.onChar x n of@@ -74,9 +96,18 @@ k <- deleteM xs j deleteNode n insertNode (G.subst x k n)+deleteM [] i = do+ n <- nodeBy i+ w <- nodeBy (G.eps n)+ deleteNode w+ deleteNode n+ j <- insertLeaf+ insertNode (n { G.eps = j }) lookupM :: String -> Id -> GraphM a (Maybe a)-lookupM [] i = G.value <$> nodeBy i+lookupM [] i = do+ j <- G.eps <$> nodeBy i+ G.unValue <$> nodeBy j lookupM (x:xs) i = do n <- nodeBy i case G.onChar x n of@@ -99,7 +130,7 @@ -- | Empty DAWG. empty :: Ord a => DAWG a empty = - let (i, g) = G.insert leaf G.empty+ let (i, g) = S.runState insertLeaf G.empty in DAWG g i -- | Number of states in the underlying graph.@@ -112,6 +143,15 @@ let (i, g) = S.runState (insertM xs y $ root d) (graph d) in DAWG g i +-- | Insert with a function, combining new value and old value.+-- 'insertWith' f key value d will insert the pair (key, value) into d if+-- key does not exist in the DAWG. If the key does exist, the function+-- will insert the pair (key, f new_value old_value).+insertWith :: Ord a => (a -> a -> a) -> String -> a -> DAWG a -> DAWG a+insertWith f xs y d =+ let (i, g) = S.runState (insertWithM f xs y $ root d) (graph d)+ in DAWG g i+ -- | Delete the key from the DAWG. delete :: Ord a => String -> DAWG a -> DAWG a delete xs d =@@ -126,6 +166,14 @@ fromList :: Ord a => [(String, a)] -> DAWG a fromList xs = let update t (x, v) = insert x v t+ in foldl' update empty xs++-- | Construct DAWG from the list of (word, value) pairs+-- with a combining function. The combining function is+-- applied strictly.+fromListWith :: Ord a => (a -> a -> a) -> [(String, a)] -> DAWG a+fromListWith f xs =+ let update t (x, v) = insertWith f x v t in foldl' update empty xs -- | Make DAWG from the list of words. Annotate each word with
Data/DAWG/Graph.hs view
@@ -23,7 +23,7 @@ ) where import Control.Applicative ((<$>), (<*>))-import Data.Binary (Binary, put, get)+import Data.Binary (Binary, Get, put, get) import qualified Data.Map as M import qualified Data.IntSet as IS import qualified Data.IntMap as IM@@ -37,26 +37,40 @@ -- consequently, they must be represented as one node in the graph) -- iff they are equal with respect to their values and outgoing -- edges.-data Node a = Node- { value :: !a- , edges :: !(V.VMap Id) }+--+-- Invariant: the 'value' identifier always points to the 'Value' node.+-- 'edges', on the other hand, point to 'Branch' nodes.+data Node a+ = Branch+ { eps :: {-# UNPACK #-} !Id+ , edges :: !(V.VMap Id) }+ | Value+ { unValue :: !a } deriving (Show, Eq, Ord) instance Functor Node where- fmap f n = n { value = f (value n) }+ fmap f (Value x) = Value (f x)+ fmap _ (Branch x y) = Branch x y instance Binary a => Binary (Node a) where- put Node{..} = put value >> put edges- get = Node <$> get <*> get+ put Branch{..} = put (1 :: Int) >> put eps >> put edges+ put Value{..} = put (2 :: Int) >> put unValue+ get = do+ x <- get :: Get Int+ case x of+ 1 -> Branch <$> get <*> get+ _ -> Value <$> get -- | Identifier of the child determined by the given character. onChar :: Char -> Node a -> Maybe Id-onChar x n = V.lookup x (edges n)+onChar x (Branch _ es) = V.lookup x es+onChar _ (Value _) = error "onChar: value node" -- | Substitue the identifier of the child determined by the given -- character. subst :: Char -> Id -> Node a -> Node a-subst x i n = n { edges = V.insert x i (edges n) }+subst x i (Branch w es) = Branch w (V.insert x i es)+subst _ _ (Value _) = error "subst: value node" -- | A set of nodes. To every node a unique identifier is assigned. -- Invariants:
− Data/DAWG/Wrapper.hs
@@ -1,62 +0,0 @@--- | The module provides a wrapper over the 'D.DAWG' with separate--- 'C.Codec' for values encoding, which is beneficial when the set--- of possible DAWG values is small but individual values occupy--- a lot of memory.--- NOTE: Useless values are not deleted from the codec when--- deleting the DAWG entry.--module Data.DAWG.Wrapper-( DAWG (..)-, empty-, numStates-, insert-, delete-, lookup-, fromList-, fromLang-) where--import Prelude hiding (lookup)-import Data.List (foldl')-import qualified Control.Monad.Codec as C-import qualified Data.DAWG as D---- | A plain 'D.DAWG' with separate 'C.Codec' for values encoding.-data DAWG a = DAWG- { dawg :: !(D.DAWG Int)- , codec :: !(C.AtomCodec a) }---- | Empty DAWG.-empty :: DAWG a-empty = DAWG D.empty C.empty---- | Number of states in the underlying graph.-numStates :: DAWG a -> Int-numStates = D.numStates . dawg---- | Insert the (key, value) pair into the DAWG.-insert :: Ord a => String -> a -> DAWG a -> DAWG a-insert xs y d =- let (y', c') = C.runCodec (codec d) (C.encode C.idLens y)- in DAWG (D.insert xs y' (dawg d)) c'---- | Delete the key from the DAWG.-delete :: Ord a => String -> DAWG a -> DAWG a-delete xs d = DAWG (D.delete xs (dawg d)) (codec d)---- | Find value associated with the key.-lookup :: Ord a => String -> DAWG a -> Maybe a-lookup xs d =- D.lookup xs (dawg d) >>=- C.evalCodec (codec d) . C.maybeDecode C.idLens---- | Construct DAWG from the list of (word, value) pairs.-fromList :: Ord a => [(String, a)] -> DAWG a-fromList xs =- let update t (x, v) = insert x v t- in foldl' update empty xs---- | Make DAWG from the list of words. Annotate each word with--- the @()@ value.-fromLang :: [String] -> DAWG ()-fromLang xs = fromList [(x, ()) | x <- xs]
dawg.cabal view
@@ -1,13 +1,9 @@ name: dawg-version: 0.3.0+version: 0.4.0 synopsis: Directed acyclic word graphs description: The library implements /directed acyclic word graphs/ (DAWGs), which can- be also interpreted as /minimal acyclic finite-state automata/. - .- In most cases you can use the "Data.DAWG" module which provides the basic- implementation of DAWGs. If values have substantial memory footprint- consider using the "Data.DAWG.Wrapper" module instead.+ be also interpreted as /minimal acyclic finite-state automata/. license: BSD3 license-file: LICENSE cabal-version: >= 1.6@@ -27,11 +23,9 @@ , vector , vector-binary , mtl- , monad-codec >= 0.2 && < 0.3 exposed-modules: Data.DAWG- , Data.DAWG.Wrapper , Data.DAWG.Graph , Data.DAWG.VMap