| 36 | Model::~Model() {} |
| 37 | |
| 38 | std::vector<std::pair<absl::string_view, int>> Model::SampleEncode( |
| 39 | absl::string_view normalized, float alpha) const { |
| 40 | if (!status().ok() || normalized.empty()) { |
| 41 | return {}; |
| 42 | } |
| 43 | |
| 44 | struct SymbolPair { |
| 45 | int left; // left index of this pair |
| 46 | int right; // right index of this pair |
| 47 | float score; // score of this pair. large is better. |
| 48 | size_t size; // length of this piece |
| 49 | }; |
| 50 | |
| 51 | class SymbolPairComparator { |
| 52 | public: |
| 53 | const bool operator()(SymbolPair *h1, SymbolPair *h2) { |
| 54 | return (h1->score < h2->score || |
| 55 | (h1->score == h2->score && h1->left > h2->left)); |
| 56 | } |
| 57 | }; |
| 58 | |
| 59 | struct Symbol { |
| 60 | int prev; // prev index of this symbol. -1 for BOS. |
| 61 | int next; // next index of tihs symbol. -1 for EOS. |
| 62 | bool freeze; // this symbol is never be merged. |
| 63 | absl::string_view piece; |
| 64 | }; |
| 65 | |
| 66 | using Agenda = std::priority_queue<SymbolPair *, std::vector<SymbolPair *>, |
| 67 | SymbolPairComparator>; |
| 68 | Agenda agenda; |
| 69 | std::vector<Symbol> symbols; |
| 70 | symbols.reserve(normalized.size()); |
| 71 | |
| 72 | // Reverse merge rules. |
| 73 | // key: merged symbol, value: pair of original symbols. |
| 74 | absl::flat_hash_map<absl::string_view, |
| 75 | std::pair<absl::string_view, absl::string_view>> |
| 76 | rev_merge; |
| 77 | |
| 78 | // Pre-allocates SymbolPair for efficiency. |
| 79 | constexpr size_t kPreallocateSymbolPairSize = 256; |
| 80 | model::FreeList<SymbolPair> symbol_pair_allocator(kPreallocateSymbolPairSize); |
| 81 | |
| 82 | // Lookup new symbol pair at [left, right] and inserts it to agenda. |
| 83 | auto MaybeAddNewSymbolPair = [this, &symbol_pair_allocator, &symbols, &agenda, |
| 84 | &rev_merge](int left, int right) { |
| 85 | if (left == -1 || right == -1 || symbols[left].freeze || |
| 86 | symbols[right].freeze) |
| 87 | return; |
| 88 | const absl::string_view piece( |
| 89 | symbols[left].piece.data(), |
| 90 | symbols[left].piece.size() + symbols[right].piece.size()); |
| 91 | const auto it = pieces_.find(piece); |
| 92 | if (it == pieces_.end()) { |
| 93 | return; |
| 94 | } |
| 95 | auto *h = symbol_pair_allocator.Allocate(); |