Coverage Report

Created: 2026-09-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_