/src/tesseract/src/ccutil/ambigs.h
Line | Count | Source |
1 | | /////////////////////////////////////////////////////////////////////// |
2 | | // File: ambigs.h |
3 | | // Description: Constants, flags, functions for dealing with |
4 | | // ambiguities (training and recognition). |
5 | | // Author: Daria Antonova |
6 | | // |
7 | | // (C) Copyright 2008, Google Inc. |
8 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
9 | | // you may not use this file except in compliance with the License. |
10 | | // You may obtain a copy of the License at |
11 | | // http://www.apache.org/licenses/LICENSE-2.0 |
12 | | // Unless required by applicable law or agreed to in writing, software |
13 | | // distributed under the License is distributed on an "AS IS" BASIS, |
14 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | | // See the License for the specific language governing permissions and |
16 | | // limitations under the License. |
17 | | // |
18 | | /////////////////////////////////////////////////////////////////////// |
19 | | |
20 | | #ifndef TESSERACT_CCUTIL_AMBIGS_H_ |
21 | | #define TESSERACT_CCUTIL_AMBIGS_H_ |
22 | | |
23 | | #ifdef HAVE_CONFIG_H |
24 | | # include "config_auto.h" // DISABLED_LEGACY_ENGINE |
25 | | #endif |
26 | | |
27 | | #if !defined(DISABLED_LEGACY_ENGINE) |
28 | | |
29 | | # include <tesseract/unichar.h> |
30 | | # include "elst.h" |
31 | | # include "tprintf.h" |
32 | | # include "unicharset.h" |
33 | | |
34 | | # include <array> |
35 | | # include <string> |
36 | | |
37 | | namespace tesseract { |
38 | | |
39 | | constexpr int kMaxAmbigSize = 10; |
40 | | |
41 | | using UnicharIdVector = std::vector<UNICHAR_ID>; |
42 | | |
43 | | enum AmbigType { |
44 | | NOT_AMBIG, // the ngram pair is not ambiguous |
45 | | REPLACE_AMBIG, // ocred ngram should always be substituted with correct |
46 | | DEFINITE_AMBIG, // add correct ngram to the classifier results (1-1) |
47 | | SIMILAR_AMBIG, // use pairwise classifier for ocred/correct pair (1-1) |
48 | | CASE_AMBIG, // this is a case ambiguity (1-1) |
49 | | |
50 | | AMBIG_TYPE_COUNT // number of enum entries |
51 | | }; |
52 | | |
53 | | // A collection of utility functions for arrays of UNICHAR_IDs that are |
54 | | // terminated by INVALID_UNICHAR_ID. |
55 | | class UnicharIdArrayUtils { |
56 | | public: |
57 | | // Compares two arrays of unichar ids. Returns -1 if the length of array1 is |
58 | | // less than length of array2, if any array1[i] is less than array2[i]. |
59 | | // Returns 0 if the arrays are equal, 1 otherwise. |
60 | | // The function assumes that the arrays are terminated by INVALID_UNICHAR_ID. |
61 | 566M | static inline int compare(const UNICHAR_ID *ptr1, const UNICHAR_ID *ptr2) { |
62 | 1.13G | for (;;) { |
63 | 1.13G | const UNICHAR_ID val1 = *ptr1++; |
64 | 1.13G | const UNICHAR_ID val2 = *ptr2++; |
65 | 1.13G | if (val1 != val2) { |
66 | 564M | if (val1 == INVALID_UNICHAR_ID) { |
67 | 5.24M | return -1; |
68 | 5.24M | } |
69 | 559M | if (val2 == INVALID_UNICHAR_ID) { |
70 | 116 | return 1; |
71 | 116 | } |
72 | 559M | if (val1 < val2) { |
73 | 14.1M | return -1; |
74 | 14.1M | } |
75 | 545M | return 1; |
76 | 559M | } |
77 | 573M | if (val1 == INVALID_UNICHAR_ID) { |
78 | 1.87M | return 0; |
79 | 1.87M | } |
80 | 573M | } |
81 | 566M | } |
82 | | |
83 | | // Copies UNICHAR_IDs from dst to src. Returns the number of ids copied. |
84 | | // The function assumes that the arrays are terminated by INVALID_UNICHAR_ID |
85 | | // and that dst has enough space for all the elements from src. |
86 | 76.1k | static inline int copy(const UNICHAR_ID src[], UNICHAR_ID dst[]) { |
87 | 76.1k | int i = 0; |
88 | 303k | do { |
89 | 303k | dst[i] = src[i]; |
90 | 303k | } while (dst[i++] != INVALID_UNICHAR_ID); |
91 | 76.1k | return i - 1; |
92 | 76.1k | } |
93 | | |
94 | | // Prints unichars corresponding to the unichar_ids in the given array. |
95 | | // The function assumes that array is terminated by INVALID_UNICHAR_ID. |
96 | 0 | static inline void print(const UNICHAR_ID array[], const UNICHARSET &unicharset) { |
97 | 0 | const UNICHAR_ID *ptr = array; |
98 | 0 | if (*ptr == INVALID_UNICHAR_ID) { |
99 | 0 | tprintf("[Empty]"); |
100 | 0 | } |
101 | 0 | while (*ptr != INVALID_UNICHAR_ID) { |
102 | 0 | tprintf("%s ", unicharset.id_to_unichar(*ptr++)); |
103 | 0 | } |
104 | 0 | tprintf("( "); |
105 | 0 | ptr = array; |
106 | 0 | while (*ptr != INVALID_UNICHAR_ID) { |
107 | 0 | tprintf("%d ", *ptr++); |
108 | 0 | } |
109 | 0 | tprintf(")\n"); |
110 | 0 | } |
111 | | }; |
112 | | |
113 | | // AMBIG_SPEC_LIST stores a list of dangerous ambigs that |
114 | | // start with the same unichar (e.g. r->t rn->m rr1->m). |
115 | | class AmbigSpec : public ELIST<AmbigSpec>::LINK { |
116 | | public: |
117 | | AmbigSpec(); |
118 | | ~AmbigSpec() = default; |
119 | | |
120 | | // Comparator function for sorting AmbigSpec_LISTs. The lists will |
121 | | // be sorted by their wrong_ngram arrays. Example of wrong_ngram vectors |
122 | | // in a sorted AmbigSpec_LIST: [9 1 3], [9 3 4], [9 8], [9, 8 1]. |
123 | 10.5M | static int compare_ambig_specs(const AmbigSpec *s1, const AmbigSpec *s2) { |
124 | 10.5M | int result = UnicharIdArrayUtils::compare(s1->wrong_ngram.data(), s2->wrong_ngram.data()); |
125 | 10.5M | if (result != 0) { |
126 | 10.5M | return result; |
127 | 10.5M | } |
128 | 436 | return UnicharIdArrayUtils::compare(s1->correct_fragments.data(), s2->correct_fragments.data()); |
129 | 10.5M | } |
130 | | |
131 | | std::array<UNICHAR_ID, kMaxAmbigSize + 1> wrong_ngram; |
132 | | std::array<UNICHAR_ID, kMaxAmbigSize + 1> correct_fragments; |
133 | | UNICHAR_ID correct_ngram_id; |
134 | | AmbigType type; |
135 | | int wrong_ngram_size; |
136 | | }; |
137 | | ELISTIZEH(AmbigSpec) |
138 | | |
139 | | // AMBIG_TABLE[i] stores a set of ambiguities whose |
140 | | // wrong ngram starts with unichar id i. |
141 | | using UnicharAmbigsVector = std::vector<AmbigSpec_LIST *>; |
142 | | |
143 | | class UnicharAmbigs { |
144 | | public: |
145 | 8 | UnicharAmbigs() = default; |
146 | 0 | ~UnicharAmbigs() { |
147 | 0 | for (auto data : replace_ambigs_) { |
148 | 0 | delete data; |
149 | 0 | } |
150 | 0 | for (auto data : dang_ambigs_) { |
151 | 0 | delete data; |
152 | 0 | } |
153 | 0 | for (auto data : one_to_one_definite_ambigs_) { |
154 | 0 | delete data; |
155 | 0 | } |
156 | 0 | } |
157 | | |
158 | 757k | const UnicharAmbigsVector &dang_ambigs() const { |
159 | 757k | return dang_ambigs_; |
160 | 757k | } |
161 | 757k | const UnicharAmbigsVector &replace_ambigs() const { |
162 | 757k | return replace_ambigs_; |
163 | 757k | } |
164 | | |
165 | | // Initializes the ambigs by adding a nullptr pointer to each table. |
166 | | void InitUnicharAmbigs(const UNICHARSET &unicharset, bool use_ambigs_for_adaption); |
167 | | |
168 | | // Loads the universal ambigs that are useful for any language. |
169 | | void LoadUniversal(const UNICHARSET &encoder_set, UNICHARSET *unicharset); |
170 | | |
171 | | // Fills in two ambiguity tables (replaceable and dangerous) with information |
172 | | // read from the ambigs file. An ambiguity table is an array of lists. |
173 | | // The array is indexed by a class id. Each entry in the table provides |
174 | | // a list of potential ambiguities which can start with the corresponding |
175 | | // character. For example the ambiguity "rn -> m", would be located in the |
176 | | // table at index of unicharset.unichar_to_id('r'). |
177 | | // In 1-1 ambiguities (e.g. s -> S, 1 -> I) are recorded in |
178 | | // one_to_one_definite_ambigs_. This vector is also indexed by the class id |
179 | | // of the wrong part of the ambiguity and each entry contains a vector of |
180 | | // unichar ids that are ambiguous to it. |
181 | | // encoder_set is used to encode the ambiguity strings, undisturbed by new |
182 | | // unichar_ids that may be created by adding the ambigs. |
183 | | void LoadUnicharAmbigs(const UNICHARSET &encoder_set, TFile *ambigs_file, int debug_level, |
184 | | bool use_ambigs_for_adaption, UNICHARSET *unicharset); |
185 | | |
186 | | // Returns definite 1-1 ambigs for the given unichar id. |
187 | 0 | inline const UnicharIdVector *OneToOneDefiniteAmbigs(UNICHAR_ID unichar_id) const { |
188 | 0 | if (one_to_one_definite_ambigs_.empty()) { |
189 | 0 | return nullptr; |
190 | 0 | } |
191 | 0 | return one_to_one_definite_ambigs_[unichar_id]; |
192 | 0 | } |
193 | | |
194 | | // Returns a pointer to the vector with all unichar ids that appear in the |
195 | | // 'correct' part of the ambiguity pair when the given unichar id appears |
196 | | // in the 'wrong' part of the ambiguity. E.g. if DangAmbigs file consist of |
197 | | // m->rn,rn->m,m->iii, UnicharAmbigsForAdaption() called with unichar id of |
198 | | // m will return a pointer to a vector with unichar ids of r,n,i. |
199 | 0 | inline const UnicharIdVector *AmbigsForAdaption(UNICHAR_ID unichar_id) const { |
200 | 0 | if (ambigs_for_adaption_.empty()) { |
201 | 0 | return nullptr; |
202 | 0 | } |
203 | 0 | return ambigs_for_adaption_[unichar_id]; |
204 | 0 | } |
205 | | |
206 | | // Similar to the above, but return the vector of unichar ids for which |
207 | | // the given unichar_id is an ambiguity (appears in the 'wrong' part of |
208 | | // some ambiguity pair). |
209 | 107 | inline const UnicharIdVector *ReverseAmbigsForAdaption(UNICHAR_ID unichar_id) const { |
210 | 107 | if (reverse_ambigs_for_adaption_.empty()) { |
211 | 107 | return nullptr; |
212 | 107 | } |
213 | 0 | return reverse_ambigs_for_adaption_[unichar_id]; |
214 | 107 | } |
215 | | |
216 | | private: |
217 | | bool ParseAmbiguityLine(int line_num, int version, int debug_level, const UNICHARSET &unicharset, |
218 | | char *buffer, int *test_ambig_part_size, UNICHAR_ID *test_unichar_ids, |
219 | | int *replacement_ambig_part_size, std::string &replacement_string, int *type); |
220 | | bool InsertIntoTable(UnicharAmbigsVector &table, int test_ambig_part_size, |
221 | | UNICHAR_ID *test_unichar_ids, int replacement_ambig_part_size, |
222 | | const std::string &replacement_string, int type, AmbigSpec *ambig_spec, |
223 | | UNICHARSET *unicharset); |
224 | | |
225 | | UnicharAmbigsVector dang_ambigs_; |
226 | | UnicharAmbigsVector replace_ambigs_; |
227 | | std::vector<UnicharIdVector *> one_to_one_definite_ambigs_; |
228 | | std::vector<UnicharIdVector *> ambigs_for_adaption_; |
229 | | std::vector<UnicharIdVector *> reverse_ambigs_for_adaption_; |
230 | | }; |
231 | | |
232 | | } // namespace tesseract |
233 | | |
234 | | #endif // !defined(DISABLED_LEGACY_ENGINE) |
235 | | |
236 | | #endif // TESSERACT_CCUTIL_AMBIGS_H_ |