File size: 1,544 Bytes
483b250
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
"""Memory-light lexicon trie for constrained beam search over large (0.5-2M word) lexicons.
A node is a (lo, hi, depth) range of the sorted word list; children are found with bisect and cached lazily, so
only nodes actually visited by the beam are ever materialised. Same interface as xlit_model.Trie (kids[n], final[n])."""
import bisect
from bhc.xlit_model import T2I, TGT_VOCAB


class _Kids:
    def __init__(s, t): s.t = t
    def __getitem__(s, n): return s.t._children(n)


class _Final:
    def __init__(s, t): s.t = t
    def __getitem__(s, n):
        lo, hi, d = s.t.nodes[n]; return len(s.t.w[lo]) == d


class LazyTrie:
    def __init__(s, words):
        s.w = sorted(w for w in set(words) if w and all(c in T2I for c in w))
        s.nodes = [(0, len(s.w), 0)]; s.ids = {s.nodes[0]: 0}; s.cache = {}
        s.kids = _Kids(s); s.final = _Final(s)

    def _children(s, n):
        c = s.cache.get(n)
        if c is not None: return c
        lo, hi, d = s.nodes[n]; w = s.w; out = {}
        pos = lo
        if pos < hi and len(w[pos]) == d: pos += 1          # the word equal to the prefix sorts first
        while pos < hi:
            ch = w[pos][d]; pre = w[pos][:d + 1]
            end = bisect.bisect_left(w, pre[:-1] + chr(ord(ch) + 1), pos, hi)
            key = (pos, end, d + 1); nid = s.ids.get(key)
            if nid is None: nid = len(s.nodes); s.nodes.append(key); s.ids[key] = nid
            out[T2I[ch]] = nid; pos = end
        if len(s.cache) > 400000: s.cache.clear()
        s.cache[n] = out; return out