-
Notifications
You must be signed in to change notification settings - Fork 94
Refactor: extract walk strategy with dynamic span support #779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,18 +25,19 @@ | |||||||||||||||||||
|
|
||||||||||||||||||||
| #include <algorithm> | ||||||||||||||||||||
| #include <chrono> | ||||||||||||||||||||
| #include <limits> | ||||||||||||||||||||
| #include <stack> | ||||||||||||||||||||
| #include <string> | ||||||||||||||||||||
| #include <utility> | ||||||||||||||||||||
| #include <vector> | ||||||||||||||||||||
|
|
||||||||||||||||||||
| #include "walk_strategy.h" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| namespace Formosa::Gramambular2 { | ||||||||||||||||||||
|
|
||||||||||||||||||||
| void ReadingGrid::clear() { | ||||||||||||||||||||
| cursor_ = 0; | ||||||||||||||||||||
| readings_.clear(); | ||||||||||||||||||||
| spans_.clear(); | ||||||||||||||||||||
| fixedSpans_.clear(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| void ReadingGrid::setCursor(size_t cursor) { | ||||||||||||||||||||
|
|
@@ -121,83 +122,55 @@ int64_t GetEpochNowInMicroseconds() { | |||||||||||||||||||
|
|
||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| } // namespace | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Find the weightiest path in the grid graph. The path represents the most | ||||||||||||||||||||
| // likely hidden chain of events from the observations. | ||||||||||||||||||||
| // We use the Viterbi algorithm to compute such path. | ||||||||||||||||||||
| // Instead of computing the path with the shortest distance, though, we compute | ||||||||||||||||||||
| // the path with the longest distance (so the weightiest), since with log | ||||||||||||||||||||
| // probability a larger value means a larger probability. The algorithm runs in | ||||||||||||||||||||
| // O(|V| + |E|) time for G = (V, E) where G is a DAG. This means the walk is | ||||||||||||||||||||
| // fairly economical even when the grid is large. | ||||||||||||||||||||
| void ReadingGrid::setWalkStrategy(std::shared_ptr<WalkStrategy> strategy) { | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| walkStrategy_ = std::move(strategy); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| void ReadingGrid::fixSpan(size_t position, NodePtr node) { | ||||||||||||||||||||
| assert(node != nullptr); | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| assert(position < readings_.size()); | ||||||||||||||||||||
| assert(position + node->spanningLength() <= readings_.size()); | ||||||||||||||||||||
| size_t newEnd = position + node->spanningLength(); | ||||||||||||||||||||
| auto it = fixedSpans_.begin(); | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| while (it != fixedSpans_.end()) { | ||||||||||||||||||||
| size_t existStart = it->first; | ||||||||||||||||||||
| size_t existEnd = existStart + it->second->spanningLength(); | ||||||||||||||||||||
| // Two spans overlap if their ranges intersect. | ||||||||||||||||||||
| if (existStart < newEnd && position < existEnd) { | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| it = fixedSpans_.erase(it); | ||||||||||||||||||||
| } else { | ||||||||||||||||||||
| ++it; | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| fixedSpans_[position] = std::move(node); | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| } | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| void ReadingGrid::clearFixedSpans() { | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| for (auto& [pos, node] : fixedSpans_) { | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| node->reset(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
| fixedSpans_.clear(); | ||||||||||||||||||||
|
Comment on lines
+147
to
+152
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The If the intention is that a fixed span "owns" its override and clearing it should also undo the override, that coupling should be documented explicitly and/or enforced structurally (e.g., clear the override before calling
Suggested change
|
||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ReadingGrid::WalkResult ReadingGrid::walk() { | ||||||||||||||||||||
| WalkResult result; | ||||||||||||||||||||
| if (spans_.empty()) { | ||||||||||||||||||||
| return result; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| int64_t start = GetEpochNowInMicroseconds(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Defines a state in the DP table. This structure tracks the maximum | ||||||||||||||||||||
| // accumulated score and the back-pointer required for path reconstruction in | ||||||||||||||||||||
| // the Viterbi algorithm. | ||||||||||||||||||||
| struct State { | ||||||||||||||||||||
| size_t fromIndex = 0; | ||||||||||||||||||||
| ReadingGrid::NodePtr fromNode = nullptr; | ||||||||||||||||||||
| double maxScore = -std::numeric_limits<double>::infinity(); | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const size_t readingLen = readings_.size(); | ||||||||||||||||||||
| std::vector<State> viterbi(readingLen + 1); | ||||||||||||||||||||
| viterbi[0].maxScore = 0.0; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Iterate through the grid and compute the maximum accumulated score for each | ||||||||||||||||||||
| // reachable position. Since the grid is a lattice where edges only point | ||||||||||||||||||||
| // forward, processing nodes in index order is equivalent to processing them | ||||||||||||||||||||
| // in topological order. | ||||||||||||||||||||
| size_t reachableStates = 0; | ||||||||||||||||||||
| size_t evaluatedEdges = 0; | ||||||||||||||||||||
| for (size_t i = 0; i < readingLen; ++i) { | ||||||||||||||||||||
| ++reachableStates; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const ReadingGrid::Span& span = spans_[i]; | ||||||||||||||||||||
| const size_t maxSpanLen = span.maxLength(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| for (size_t spanLen = 1; spanLen <= maxSpanLen; ++spanLen) { | ||||||||||||||||||||
| const ReadingGrid::NodePtr& node = span.nodeOf(spanLen); | ||||||||||||||||||||
| if (node == nullptr) { | ||||||||||||||||||||
| continue; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| ++evaluatedEdges; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Performs a relaxation on a transition. This updates the destination | ||||||||||||||||||||
| // state if the path through the current node yields a higher score than | ||||||||||||||||||||
| // the previously known best path. This is the core operation of the | ||||||||||||||||||||
| // Viterbi algorithm, adapted for finding the maximum likelihood path. | ||||||||||||||||||||
| double score = viterbi[i].maxScore + node->score(); | ||||||||||||||||||||
| State& target = viterbi[i + spanLen]; | ||||||||||||||||||||
| if (score > target.maxScore) { | ||||||||||||||||||||
| target.maxScore = score; | ||||||||||||||||||||
| target.fromNode = node; | ||||||||||||||||||||
| target.fromIndex = i; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| if (!walkStrategy_) { | ||||||||||||||||||||
| walkStrategy_ = std::make_shared<ViterbiStrategy>(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| // Vertices are the reachable states | ||||||||||||||||||||
| // Edges are the candidate word transitions | ||||||||||||||||||||
| result.vertices = reachableStates; | ||||||||||||||||||||
| result.edges = evaluatedEdges; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Reconstruct the most likely path by tracing back from the end of the grid | ||||||||||||||||||||
| // to the root using the back-pointers | ||||||||||||||||||||
| size_t totalReadingLen = 0; | ||||||||||||||||||||
| for (size_t curr = readingLen; curr > 0; curr = viterbi[curr].fromIndex) { | ||||||||||||||||||||
| assert(viterbi[curr].fromNode != nullptr); | ||||||||||||||||||||
| totalReadingLen += viterbi[curr].fromNode->spanningLength(); | ||||||||||||||||||||
| result.nodes.emplace_back(std::move(viterbi[curr].fromNode)); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| std::reverse(result.nodes.begin(), result.nodes.end()); | ||||||||||||||||||||
| assert(totalReadingLen == readingLen); | ||||||||||||||||||||
| result.totalReadings = totalReadingLen; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const std::map<size_t, NodePtr>* fixedPtr = | ||||||||||||||||||||
| fixedSpans_.empty() ? nullptr : &fixedSpans_; | ||||||||||||||||||||
| WalkStrategy::WalkInput input{spans_, readings_.size(), fixedPtr}; | ||||||||||||||||||||
| auto walkOutput = walkStrategy_->walk(input); | ||||||||||||||||||||
| result.nodes = std::move(walkOutput.nodes); | ||||||||||||||||||||
| result.totalReadings = walkOutput.totalReadings; | ||||||||||||||||||||
| result.vertices = walkOutput.vertices; | ||||||||||||||||||||
| result.edges = walkOutput.edges; | ||||||||||||||||||||
| result.elapsedMicroseconds = GetEpochNowInMicroseconds() - start; | ||||||||||||||||||||
| return result; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
|
|
@@ -292,7 +265,7 @@ void ReadingGrid::removeAffectedNodes(size_t loc) { | |||||||||||||||||||
| if (spans_.empty()) { | ||||||||||||||||||||
| return; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| size_t affectedLength = kMaximumSpanLength - 1; | ||||||||||||||||||||
| size_t affectedLength = maxSpanLength_ - 1; | ||||||||||||||||||||
| size_t begin = loc <= affectedLength ? 0 : loc - affectedLength; | ||||||||||||||||||||
| size_t end = loc >= 1 ? loc - 1 : 0; | ||||||||||||||||||||
| for (size_t i = begin; i <= end; ++i) { | ||||||||||||||||||||
|
|
@@ -333,14 +306,14 @@ bool ReadingGrid::hasNodeAt(size_t loc, size_t readingLen, | |||||||||||||||||||
|
|
||||||||||||||||||||
| void ReadingGrid::update() { | ||||||||||||||||||||
| size_t begin = | ||||||||||||||||||||
| (cursor_ <= kMaximumSpanLength) ? 0 : cursor_ - kMaximumSpanLength; | ||||||||||||||||||||
| size_t end = cursor_ + kMaximumSpanLength; | ||||||||||||||||||||
| (cursor_ <= maxSpanLength_) ? 0 : cursor_ - maxSpanLength_; | ||||||||||||||||||||
| size_t end = cursor_ + maxSpanLength_; | ||||||||||||||||||||
| if (end > readings_.size()) { | ||||||||||||||||||||
| end = readings_.size(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| for (size_t pos = begin; pos < end; pos++) { | ||||||||||||||||||||
| for (size_t len = 1; len <= kMaximumSpanLength && pos + len <= end; len++) { | ||||||||||||||||||||
| for (size_t len = 1; len <= maxSpanLength_ && pos + len <= end; len++) { | ||||||||||||||||||||
| std::string combinedReading = | ||||||||||||||||||||
| combineReading(readings_.begin() + static_cast<ptrdiff_t>(pos), | ||||||||||||||||||||
| readings_.begin() + static_cast<ptrdiff_t>(pos + len)); | ||||||||||||||||||||
|
|
@@ -419,7 +392,7 @@ std::vector<ReadingGrid::NodeInSpan> ReadingGrid::overlappingNodesAt( | |||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| size_t begin = loc - std::min(loc, kMaximumSpanLength - 1); | ||||||||||||||||||||
| size_t begin = loc - std::min(loc, maxSpanLength_ - 1); | ||||||||||||||||||||
| for (size_t i = begin; i < loc; ++i) { | ||||||||||||||||||||
| size_t beginLen = loc - i + 1; | ||||||||||||||||||||
| size_t endLen = spans_[i].maxLength(); | ||||||||||||||||||||
|
|
@@ -541,22 +514,25 @@ std::vector<std::string> ReadingGrid::WalkResult::readingsAsStrings() const { | |||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| void ReadingGrid::Span::clear() { | ||||||||||||||||||||
| nodes_.fill(nullptr); | ||||||||||||||||||||
| nodes_.clear(); | ||||||||||||||||||||
| maxLength_ = 0; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| void ReadingGrid::Span::add(const ReadingGrid::NodePtr& node) { | ||||||||||||||||||||
| assert(node->spanningLength() > 0 && | ||||||||||||||||||||
| node->spanningLength() <= kMaximumSpanLength); | ||||||||||||||||||||
| nodes_[node->spanningLength() - 1] = node; | ||||||||||||||||||||
| assert(node->spanningLength() > 0); | ||||||||||||||||||||
| size_t idx = node->spanningLength() - 1; | ||||||||||||||||||||
| if (idx >= nodes_.size()) { | ||||||||||||||||||||
| nodes_.resize(idx + 1); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| nodes_[idx] = node; | ||||||||||||||||||||
| if (node->spanningLength() >= maxLength_) { | ||||||||||||||||||||
| maxLength_ = node->spanningLength(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| void ReadingGrid::Span::removeNodesOfOrLongerThan(size_t length) { | ||||||||||||||||||||
| assert(length > 0 && length <= kMaximumSpanLength); | ||||||||||||||||||||
| for (size_t i = length - 1; i < kMaximumSpanLength; ++i) { | ||||||||||||||||||||
| assert(length > 0); | ||||||||||||||||||||
| for (size_t i = length - 1; i < nodes_.size(); ++i) { | ||||||||||||||||||||
| nodes_[i] = nullptr; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| maxLength_ = 0; | ||||||||||||||||||||
|
|
@@ -580,7 +556,10 @@ void ReadingGrid::Span::removeNodesOfOrLongerThan(size_t length) { | |||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ReadingGrid::NodePtr ReadingGrid::Span::nodeOf(size_t length) const { | ||||||||||||||||||||
| assert(length > 0 && length <= kMaximumSpanLength); | ||||||||||||||||||||
| assert(length > 0); | ||||||||||||||||||||
| if (length - 1 >= nodes_.size()) { | ||||||||||||||||||||
| return nullptr; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| return nodes_[length - 1]; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,10 +24,10 @@ | |||||||||||||||||||||||
| #ifndef SRC_ENGINE_GRAMAMBULAR2_READING_GRID_H_ | ||||||||||||||||||||||||
| #define SRC_ENGINE_GRAMAMBULAR2_READING_GRID_H_ | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| #include <array> | ||||||||||||||||||||||||
| #include <cassert> | ||||||||||||||||||||||||
| #include <cstdint> | ||||||||||||||||||||||||
| #include <functional> | ||||||||||||||||||||||||
| #include <map> | ||||||||||||||||||||||||
| #include <memory> | ||||||||||||||||||||||||
| #include <optional> | ||||||||||||||||||||||||
| #include <string> | ||||||||||||||||||||||||
|
|
@@ -47,12 +47,17 @@ namespace Formosa::Gramambular2 { | |||||||||||||||||||||||
| // While we use the terminology from hidden Markov model (HMM), the actual | ||||||||||||||||||||||||
| // implementation is a much simpler Bayesian inference, since the underlying | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
| // language model consists of only unigrams. Once we have put all plausible | ||||||||||||||||||||||||
| // unigrams as nodes on the grid, a simple DAG shortest-path walk will give us | ||||||||||||||||||||||||
| // unigrams as nodes on the grid, a simple DAG longest-path walk will give us | ||||||||||||||||||||||||
| // the maximum likelihood estimation (MLE) for the hidden values. | ||||||||||||||||||||||||
| class ReadingGrid { | ||||||||||||||||||||||||
| public: | ||||||||||||||||||||||||
| static constexpr size_t kDefaultMaxSpanLength = 8; | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
| explicit ReadingGrid(std::shared_ptr<LanguageModel> lm) | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
| : lm_(std::move(lm)) {} | ||||||||||||||||||||||||
| : lm_(std::move(lm)) { | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
| size_t lmMax = lm_.maxKeyLength(); | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
Comment on lines
+55
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The constructor body calls
Suggested change
|
||||||||||||||||||||||||
| maxSpanLength_ = lmMax > 0 ? lmMax : kDefaultMaxSpanLength; | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| void clear(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -75,9 +80,10 @@ class ReadingGrid { | |||||||||||||||||||||||
| // Delete the reading after the cursor, like Del. Cursor is unmoved. | ||||||||||||||||||||||||
| bool deleteReadingAfterCursor(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| static constexpr size_t kMaximumSpanLength = 8; | ||||||||||||||||||||||||
| static constexpr char kDefaultSeparator[] = "-"; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| [[nodiscard]] size_t maxSpanLength() const { return maxSpanLength_; } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // A Node consists of a set of unigrams, a reading, and a spanning length. | ||||||||||||||||||||||||
| // The spanning length denotes the length of the node in the grid. The grid | ||||||||||||||||||||||||
| // is responsible for constructing its nodes. For Mandarin multi-character | ||||||||||||||||||||||||
|
|
@@ -180,6 +186,16 @@ class ReadingGrid { | |||||||||||||||||||||||
| std::vector<std::string> readingsAsStrings() const; | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Set the walk strategy. Default is ViterbiStrategy. | ||||||||||||||||||||||||
| void setWalkStrategy(std::shared_ptr<class WalkStrategy> strategy); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Fix a span at the given position to the given node. The walk will be | ||||||||||||||||||||||||
| // constrained to go through this node. Last-write-wins: fixing at a position | ||||||||||||||||||||||||
| // that overlaps an existing fix clears the overlapping fix. | ||||||||||||||||||||||||
| void fixSpan(size_t position, NodePtr node); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| void clearFixedSpans(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| WalkResult walk(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| struct Candidate { | ||||||||||||||||||||||||
|
|
@@ -220,7 +236,7 @@ class ReadingGrid { | |||||||||||||||||||||||
| [[nodiscard]] size_t maxLength() const { return maxLength_; } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| protected: | ||||||||||||||||||||||||
| std::array<NodePtr, kMaximumSpanLength> nodes_; | ||||||||||||||||||||||||
| std::vector<NodePtr> nodes_; | ||||||||||||||||||||||||
| size_t maxLength_ = 0; | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
@@ -233,6 +249,7 @@ class ReadingGrid { | |||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| std::vector<Unigram> getUnigrams(const std::string& reading) override; | ||||||||||||||||||||||||
| bool hasUnigrams(const std::string& reading) override; | ||||||||||||||||||||||||
| size_t maxKeyLength() const override { return lm_->maxKeyLength(); } | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| protected: | ||||||||||||||||||||||||
| std::shared_ptr<LanguageModel> lm_; | ||||||||||||||||||||||||
|
|
@@ -246,10 +263,13 @@ class ReadingGrid { | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| protected: | ||||||||||||||||||||||||
| size_t cursor_ = 0; | ||||||||||||||||||||||||
| size_t maxSpanLength_; | ||||||||||||||||||||||||
|
tianjianjiang marked this conversation as resolved.
|
||||||||||||||||||||||||
| std::string separator_ = kDefaultSeparator; | ||||||||||||||||||||||||
| std::vector<std::string> readings_; | ||||||||||||||||||||||||
| std::vector<Span> spans_; | ||||||||||||||||||||||||
| ScoreRankedLanguageModel lm_; | ||||||||||||||||||||||||
| std::shared_ptr<class WalkStrategy> walkStrategy_; | ||||||||||||||||||||||||
| std::map<size_t, NodePtr> fixedSpans_; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Internal methods for maintaining the grid. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.