7
7
-- >>> import AtCoder.Extra.AhoCorasick qualified as AC
8
8
-- >>> import Data.Vector.Unboxed qualified as VU
9
9
-- >>> let patterns = V.fromList [VU.fromList [0, 1], VU.fromList [0, 2], VU.fromList [2, 3]]
10
- -- >>> let ac = AC.build 26 patterns
10
+ -- >>> let ac = AC.build patterns
11
11
-- >>> AC.size ac
12
12
-- 6
13
+ --
13
14
-- >>> AC.retrieve ac (VU.singleton 2)
14
15
-- 4
15
16
--
@@ -21,6 +22,7 @@ module AtCoder.Extra.AhoCorasick
21
22
next ,
22
23
nextN ,
23
24
retrieve ,
25
+ match ,
24
26
)
25
27
where
26
28
@@ -29,7 +31,7 @@ import Control.Monad (when)
29
31
import Control.Monad.Fix (fix )
30
32
import Control.Monad.ST (runST )
31
33
import Data.Foldable (for_ )
32
- import Data.IntMap .Strict qualified as IM
34
+ import Data.HashMap .Strict qualified as HM
33
35
import Data.Maybe (fromJust )
34
36
import Data.Vector qualified as V
35
37
import Data.Vector.Generic qualified as VG
@@ -50,7 +52,7 @@ data AhoCorasick = AhoCorasick
50
52
-- | Vertex -> (Char -> Vertex)
51
53
--
52
54
-- @since 1.5.3.0
53
- nextAc :: ! (V. Vector (IM. IntMap Int )),
55
+ nextAc :: ! (V. Vector (HM. HashMap Int Int )),
54
56
-- | Links to parent vertex.
55
57
--
56
58
-- @since 1.5.3.0
@@ -61,7 +63,7 @@ data AhoCorasick = AhoCorasick
61
63
suffixAc :: ! (VU. Vector Int )
62
64
}
63
65
64
- -- | \(O(\Gamma \ sum_i |S_i|)\)
66
+ -- | \(O(\sum_i |S_i| \Gamma )\)
65
67
--
66
68
-- ==== Constraints
67
69
-- - \(|S_i| > 0\)
@@ -78,7 +80,7 @@ build patterns
78
80
| VG. null patterns =
79
81
AhoCorasick
80
82
1
81
- (V. singleton IM . empty)
83
+ (V. singleton HM . empty)
82
84
(VU. replicate 1 0 )
83
85
(VU. replicate 1 0 )
84
86
| otherwise =
@@ -113,13 +115,13 @@ next ::
113
115
Int
114
116
next AhoCorasick {.. } v c0 =
115
117
let ! c' = inner c0
116
- ! v' = fromJust $ IM .lookup c' (nextAc VG. ! v)
118
+ ! v' = fromJust $ HM .lookup c' (nextAc VG. ! v)
117
119
in v'
118
120
where
119
121
inner c
120
122
-- fallback to a suffix
121
123
-- TODO: why suffixAc -> Char?
122
- | IM. notMember c (nextAc VG. ! v) = inner $! suffixAc VG. ! c
124
+ | not ( HM. member c (nextAc VG. ! v) ) = inner $! suffixAc VG. ! c
123
125
| otherwise = c
124
126
125
127
-- | \(O(|S_i|)\) Applies `next` N times for a given input string.
@@ -162,25 +164,32 @@ retrieve ::
162
164
Int
163
165
retrieve ac = nextN ac 0
164
166
165
- -- | \(O(\Gamma \sum_i |S_i|)\)
167
+ -- | \(O(|S_i|)\) TODO
168
+ --
169
+ -- @since 1.5.3.0
170
+ {-# INLINEABLE match #-}
171
+ match :: (HasCallStack ) => AhoCorasick -> VU. Vector Int -> VU. Vector (Int , Int )
172
+ match ac t = VU. empty
173
+
174
+ -- | \(O(\sum_i |S_i| \Gamma)\)
166
175
{-# INLINEABLE buildTrie #-}
167
- buildTrie :: (HasCallStack ) => V. Vector (VU. Vector Int ) -> (Int , V. Vector (IM. IntMap Int ), VU. Vector Int )
176
+ buildTrie :: (HasCallStack ) => V. Vector (VU. Vector Int ) -> (Int , V. Vector (HM. HashMap Int Int ), VU. Vector Int )
168
177
buildTrie patterns = runST $ do
169
178
let ! nMaxNodes = (1 + ) . V. sum $ V. map VU. length patterns
170
179
-- (Vertex, Char) -> Vertex
171
- nextVec <- VM. replicate nMaxNodes IM . empty
180
+ nextVec <- VM. replicate nMaxNodes HM . empty
172
181
parentVec <- VUM. replicate nMaxNodes (0 :: Int )
173
182
nNodesVec <- VUM. replicate 1 (1 :: Int )
174
183
175
184
VG. forM_ patterns $ \ pat -> do
176
185
VG. foldM'
177
186
( \ ! u c -> do
178
- v0 <- IM .lookup c <$> VGM. read nextVec u
187
+ v0 <- HM .lookup c <$> VGM. read nextVec u
179
188
case v0 of
180
189
Nothing -> do
181
190
v <- VGM. read nNodesVec 0
182
191
VGM. write nNodesVec 0 $! v + 1
183
- VGM. modify nextVec (IM . insert c v) u
192
+ VGM. modify nextVec (HM . insert c v) u
184
193
VGM. write parentVec v u
185
194
pure v
186
195
Just v -> pure v
@@ -193,15 +202,15 @@ buildTrie patterns = runST $ do
193
202
! parent <- VG. take nNodes <$> VU. unsafeFreeze parentVec
194
203
pure (nNodes, next, parent)
195
204
196
- -- | \(O(\Gamma \ sum_i |S_i|)\)
205
+ -- | \(O(\sum_i |S_i| \Gamma )\)
197
206
{-# INLINEABLE runBfs #-}
198
- runBfs :: (HasCallStack ) => Int -> V. Vector (IM. IntMap Int ) -> VU. Vector Int
207
+ runBfs :: (HasCallStack ) => Int -> V. Vector (HM. HashMap Int Int ) -> VU. Vector Int
199
208
runBfs nNodes next = VU. create $ do
200
209
-- BFS
201
210
suffixVec <- VUM. replicate nNodes (0 :: Int )
202
211
que <- Q. new @ _ @ Int nNodes
203
212
204
- for_ (IM . elems (next VG. ! 0 )) $ \ v -> do
213
+ for_ (HM . elems (next VG. ! 0 )) $ \ v -> do
205
214
when (v /= - 1 ) $ do
206
215
Q. pushBack que v
207
216
@@ -211,12 +220,12 @@ runBfs nNodes next = VU.create $ do
211
220
Nothing -> pure ()
212
221
Just u -> do
213
222
-- visit neighbors
214
- for_ (IM. assocs (next VG. ! u)) $ \ (! c, ! v) -> do
223
+ for_ (HM. toList (next VG. ! u)) $ \ (! c, ! v) -> do
215
224
Q. pushBack que v
216
225
-- find the longest suffix to continue with `c`
217
226
flip fix u $ \ suffixLoop p -> do
218
227
! suf <- VGM. read suffixVec p
219
- case IM .lookup c (next VG. ! suf) of
228
+ case HM .lookup c (next VG. ! suf) of
220
229
Just sufC -> do
221
230
VGM. write suffixVec v sufC
222
231
Nothing
0 commit comments