dawg-ord 0.4.0.2 → 0.5.0.0
raw patch · 8 files changed
+100/−90 lines, 8 filesdep +HUnitdep +dawg-orddep +smallcheck
Dependencies added: HUnit, dawg-ord, smallcheck, tasty, tasty-hunit, tasty-quickcheck, tasty-smallcheck
Files
- dawg-ord.cabal +30/−5
- src/Data/DAWG/Gen/Types.hs +3/−3
- src/Data/DAWG/Int.hs +6/−4
- src/Data/DAWG/Int/Dynamic.hs +31/−54
- src/Data/DAWG/Int/Dynamic/Internal.hs +5/−9
- src/Data/DAWG/Ord.hs +1/−1
- src/Data/DAWG/Ord/Dynamic.hs +15/−14
- tests/test.hs +9/−0
dawg-ord.cabal view
@@ -1,20 +1,20 @@ name: dawg-ord-version: 0.4.0.2+version: 0.5.0.0 synopsis: Directed acyclic word graphs description: The library implements /directed acyclic word graphs/ (DAWGs) internally represented as /minimal acyclic deterministic finite-state automata/.- The implemented version of DAWG is, semantically, a map from+ The implemented version of DAWG can be seen as a map from sequences of alphabet symbols (keys) to values. . The library allows to build DAWGs over any symbols and values provided that they both have `Ord` instances (see the- `Data.DAWG.Ord` module).+ "Data.DAWG.Ord" module). It also provides a fast insert operation which can be used to construct DAWGs on-the-fly. license: BSD3 license-file: LICENSE-cabal-version: >= 1.6+cabal-version: >= 1.10 copyright: Copyright (c) 2015 Jakub Waszczuk author: Jakub Waszczuk maintainer: waszczuk.kuba@gmail.com@@ -24,10 +24,12 @@ build-type: Simple library+ default-language:+ Haskell2010 hs-source-dirs: src build-depends: base >= 4 && < 5- , containers >= 0.4.1 && < 0.6+ , containers >= 0.5 && < 0.6 , vector >= 0.10 && < 0.12 , mtl >= 2.1 && < 2.3 , transformers >= 0.3 && < 0.5@@ -51,6 +53,29 @@ , Data.DAWG.Gen.Util ghc-options: -Wall+++test-suite test+ default-language:+ Haskell2010+ type:+ exitcode-stdio-1.0+ hs-source-dirs:+ tests+ main-is:+ test.hs+ build-depends:+ dawg-ord+ , base >= 4 && < 5+ , containers >= 0.5 && < 0.6+ , mtl >= 2.1 && < 2.3+ , tasty >= 0.10+ , smallcheck >= 1.1+ , tasty-smallcheck >= 0.8+ , tasty-quickcheck >= 0.8+ , tasty-hunit >= 0.9+ , HUnit >= 1.2+ source-repository head type: git
src/Data/DAWG/Gen/Types.hs view
@@ -6,11 +6,11 @@ , Val ) where --- | Node identifier.+-- | Identifier of a DAWG node (automaton state). type ID = Int --- | Internal representation of an alphabet element.+-- | A transition symbol. type Sym = Int --- | Internal representation of an automaton value.+-- | A type of DAWG values, stored in accept states. type Val = Int
src/Data/DAWG/Int.hs view
@@ -1,10 +1,11 @@ -- | The module implements /directed acyclic word graphs/ (DAWGs) internaly -- represented as /minimal acyclic deterministic finite-state automata/.--- The implementation provides a fast insert operation which can be--- used to build the DAWG structure incrementaly.+-- The implementation provides fast insert and delete operations+-- which can be used to build the DAWG structure incrementaly. ----- Keys and values must provide an 'Enum' instance; see the--- 'Data.DAWG.Ord' module if you look for a more generic solution.+-- See the "Data.DAWG.Ord" module if you look for a more generic+-- solution (which, for the moment, lacks some of the functionality provided+-- here, e.g. the `delete` function). module Data.DAWG.Int@@ -12,6 +13,7 @@ -- * DAWG type DAWG , ID+, Sym , Val , root
src/Data/DAWG/Int/Dynamic.hs view
@@ -176,27 +176,26 @@ -- | Empty DAWG.-empty :: DAWG a+empty :: DAWG empty = let (i, g) = S.runState insertLeaf G.empty in DAWG g i -- | Number of states in the automaton.-numStates :: DAWG a -> Int+numStates :: DAWG -> Int numStates = G.size . graph --- | Number of edges in the automaton.-numEdges :: DAWG a -> Int+-- | Number of transitions in the automaton.+numEdges :: DAWG -> Int numEdges = sum . map (length . N.edges) . G.nodes . graph -- | Insert the (key, value) pair into the DAWG.-insert :: Enum a => [a] -> Val -> DAWG a -> DAWG a-insert xs' y d =- let xs = map fromEnum xs'- (i, g) = S.runState (insertM xs y $ root d) (graph d)+insert :: [Sym] -> Val -> DAWG -> DAWG+insert xs y d =+ let (i, g) = S.runState (insertM xs y $ root d) (graph d) in DAWG g i {-# INLINE insert #-} @@ -206,32 +205,23 @@ -- 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- :: Enum a => (Val -> Val -> Val)- -> [a] -> Val -> DAWG a -> DAWG a-insertWith f xs' y d =- let xs = map fromEnum xs'- (i, g) = S.runState (insertWithM f xs y $ root d) (graph d)+ :: (Val -> Val -> Val)+ -> [Sym] -> Val -> DAWG -> DAWG+insertWith f xs y d =+ let (i, g) = S.runState (insertWithM f xs y $ root d) (graph d) in DAWG g i-{-# SPECIALIZE insertWith- :: (Val -> Val -> Val) -> String -> Val- -> DAWG Char -> DAWG Char #-} -- | Delete the key from the DAWG.-delete :: Enum a => [a] -> DAWG a -> DAWG a-delete xs' d =- let xs = map fromEnum xs'- (i, g) = S.runState (deleteM xs $ root d) (graph d)+delete :: [Sym] -> DAWG -> DAWG+delete xs d =+ let (i, g) = S.runState (deleteM xs $ root d) (graph d) in DAWG g i-{-# SPECIALIZE delete :: String -> DAWG Char -> DAWG Char #-} -- | Find value associated with the key.-lookup :: Enum a => [a] -> DAWG a -> Maybe Val-lookup xs' d =- let xs = map fromEnum xs'- in S.evalState (lookupM xs $ root d) (graph d)-{-# SPECIALIZE lookup :: String -> DAWG Char -> Maybe Val #-}+lookup :: [Sym] -> DAWG -> Maybe Val+lookup xs d = S.evalState (lookupM xs $ root d) (graph d) -- -- | Find all (key, value) pairs such that key is prefixed@@ -248,51 +238,40 @@ -- | Return all key/value pairs in the DAWG in ascending key order.-assocs :: Enum a => DAWG a -> [([a], Val)]-assocs- = map (first (map toEnum))- . (subPairs <$> graph <*> root)-{-# SPECIALIZE assocs :: DAWG Char -> [(String, Val)] #-}+assocs :: DAWG -> [([Sym], Val)]+assocs = subPairs <$> graph <*> root -- | Return all keys of the DAWG in ascending order.-keys :: Enum a => DAWG a -> [[a]]+keys :: DAWG -> [[Sym]] keys = map fst . assocs-{-# SPECIALIZE keys :: DAWG Char -> [String] #-} -- | Return all elements of the DAWG in the ascending order of their keys.-elems :: DAWG a -> [Val]+elems :: DAWG -> [Val] elems = map snd . (subPairs <$> graph <*> root) --- | Construct DAWG from the list of (word, value) pairs.-fromList :: Enum a => [([a], Val)] -> DAWG a+-- | Construct DAWG from the list of (key, value) pairs.+fromList :: [([Sym], Val)] -> DAWG fromList xs = let update t (x, v) = insert x v t in foldl' update empty xs-{-# INLINE fromList #-} --- | Construct DAWG from the list of (word, value) pairs+-- | Construct DAWG from the list of (key, value) pairs -- with a combining function. The combining function is -- applied strictly.-fromListWith- :: Enum a => (Val -> Val -> Val)- -> [([a], Val)] -> DAWG a+fromListWith :: (Val -> Val -> Val) -> [([Sym], Val)] -> DAWG fromListWith f xs = let update t (x, v) = insertWith f x v t in foldl' update empty xs-{-# SPECIALIZE fromListWith- :: (Val -> Val -> Val)- -> [(String, Val)] -> DAWG Char #-} --- | Make DAWG from the list of words. Annotate each word with--- the @()@ value.-fromLang :: Enum a => [[a]] -> DAWG a+-- | Make DAWG from the list of words (by annotating each word with+-- a dummy value).+fromLang :: [[Sym]] -> DAWG fromLang xs = fromList [(x, 0) | x <- xs]-{-# SPECIALIZE fromLang :: [String] -> DAWG Char #-} ------------------------------------------------------------@@ -301,24 +280,22 @@ -- | A list of outgoing edges (automaton transitions).-edges :: Enum a => ID -> DAWG a -> [(a, ID)]+edges :: ID -> DAWG -> [(Sym, ID)] edges i = map (first toEnum) . N.edges . G.nodeBy i . graph-{-# SPECIALIZE edges :: ID -> DAWG Char -> [(Char, ID)] #-}-{-# SPECIALIZE edges :: ID -> DAWG Int -> [(Int, ID)] #-} -- | Value stored in the given automaton state.-value :: ID -> DAWG a -> Maybe Val+value :: ID -> DAWG -> Maybe Val value i = N.value . G.nodeBy i . graph -- | Follow a transition with the given symbol from the given state.-follow :: Enum a => ID -> a -> DAWG a -> Maybe ID+follow :: ID -> Sym -> DAWG -> Maybe ID follow i x DAWG{..} = flip S.evalState graph $ runMaybeT $- followPath [fromEnum x] i+ followPath [x] i ------------------------------------------------------------
src/Data/DAWG/Int/Dynamic/Internal.hs view
@@ -16,16 +16,12 @@ import qualified Data.DAWG.Int.Dynamic.Node as N --- | A directed acyclic word graph with phantom type @a@--- representing the type of alphabet symbols (type @a@ must provide--- an 'Enum' instance).------ A DAWG is, semantically, a map from keys (sequences of @a@'s) to--- integral values.--- See 'Data.DAWG.Ord' for a more generic version of DAWGs.-data DAWG a = DAWG+-- | A directed acyclic word graph (DAWG), which can be seen as a map+-- from keys (sequences of 'Sym`'s) to values 'Val'.+-- See "Data.DAWG.Ord" for a more generic version of DAWGs.+data DAWG = DAWG { graph :: !(Graph N.Node)- -- | Root of the DAWG.+ -- | The root (start state) of the DAWG. , root :: !ID } deriving (Show, Eq, Ord)
src/Data/DAWG/Ord.hs view
@@ -1,4 +1,4 @@--- | A version of 'Data.DAWG.Int' adapted to keys and values with+-- | A version of "Data.DAWG.Int" adapted to keys and values with -- 'Ord' instances.
src/Data/DAWG/Ord/Dynamic.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE RecordWildCards #-} --- | A version of 'Data.DAWG.Int.Dynamic' adapted to+-- | A version of "Data.DAWG.Int.Dynamic" adapted to -- keys and values with 'Ord' instances. @@ -56,10 +56,10 @@ -- the type of alphabet symbols (over which keys are constructed) -- and type @b@ -- the type of values. ----- A DAWG is, semantically, a map from keys (sequences of @a@'s) to+-- A DAWG can be seen as a map from keys (sequences of @a@'s) to -- values @b@. data DAWG a b = DAWG- { intDAWG :: D.DAWG Sym+ { intDAWG :: D.DAWG , symMap :: M.Map a Int , symMapR :: M.Map Int a , valMap :: M.Map b Int@@ -67,7 +67,7 @@ } deriving (Show, Eq, Ord) --- | Root of the DAWG.+-- | The root (start state) of the DAWG. root :: DAWG a b -> ID root = D.root . intDAWG @@ -103,9 +103,10 @@ -- TODO: We could optimize it. addVal :: Ord b => b -> DM a b Int addVal x = S.state $ \dawg@DAWG{..} ->- let y = case M.lookup x valMap of- Nothing -> M.size valMap- Just k -> k+ let y = fromMaybe (M.size valMap) (M.lookup x valMap)+-- let y = case M.lookup x valMap of+-- Nothing -> M.size valMap+-- Just k -> k in (y, dawg { valMap = M.insert x y valMap , valMapR = M.insert y x valMapR })@@ -125,12 +126,12 @@ empty = DAWG D.empty M.empty M.empty M.empty M.empty --- | Number of states in the automaton.+-- | Number of states in the underlying automaton. numStates :: DAWG a b -> Int numStates = D.numStates . intDAWG --- | Number of edges in the automaton.+-- | Number of transitions in the underlying automaton. numEdges :: DAWG a b -> Int numEdges = D.numEdges . intDAWG @@ -168,14 +169,14 @@ -- | Find value associated with the key. lookup :: (Ord a, Ord b) => [a] -> DAWG a b -> Maybe b lookup xs0 DAWG{..} = do- xs <- mapM (flip M.lookup symMap) xs0+ xs <- mapM (`M.lookup` symMap) xs0 y <- D.lookup xs intDAWG M.lookup y valMapR -- | Return all key/value pairs in the DAWG in ascending key order. assocs :: DAWG a b -> [([a], b)]-assocs DAWG{..} = +assocs DAWG{..} = [ (decodeKey xs, decodeVal y) | (xs, y) <- D.assocs intDAWG ] where@@ -194,15 +195,15 @@ elems = map snd . assocs --- | Construct DAWG from the list of (word, value) pairs.+-- | Construct DAWG from the list of (key, value) pairs. fromList :: (Ord a, Ord b) => [([a], b)] -> DAWG a b 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.+-- | Make DAWG from the list of words (annotate each word with+-- the @()@ value). fromLang :: Ord a => [[a]] -> DAWG a () fromLang xs = fromList [(x, ()) | x <- xs]
+ tests/test.hs view
@@ -0,0 +1,9 @@+import Test.Tasty (defaultMain, testGroup)++import qualified Ord+++main :: IO ()+main = defaultMain $ testGroup "Tests"+ [ Ord.tests+ ]