FST  openfst-1.8.3
OpenFst Library
test-properties.h
Go to the documentation of this file.
1 // Copyright 2005-2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the 'License');
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an 'AS IS' BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // See www.openfst.org for extensive documentation on this weighted
16 // finite-state transducer library.
17 //
18 // Functions to manipulate and test property bits.
19 
20 #ifndef FST_TEST_PROPERTIES_H_
21 #define FST_TEST_PROPERTIES_H_
22 
23 #include <cstdint>
24 #include <optional>
25 #include <vector>
26 
27 #include <fst/flags.h>
28 #include <fst/log.h>
29 #include <fst/cc-visitors.h>
30 #include <fst/dfs-visit.h>
31 #include <fst/fst.h>
32 #include <fst/properties.h>
33 #include <fst/util.h>
34 #include <unordered_set>
35 
36 DECLARE_bool(fst_verify_properties);
37 
38 namespace fst {
39 namespace internal {
40 
41 // Computes FST property values defined in properties.h. The value of each
42 // property indicated in the mask will be determined and returned (these will
43 // never be unknown here). In the course of determining the properties
44 // specifically requested in the mask, certain other properties may be
45 // determined (those with little additional expense) and their values will be
46 // returned as well. The complete set of known properties (whether true or
47 // false) determined by this operation will be assigned to the value pointed
48 // to by KNOWN. 'mask & required_mask' is used to determine whether the stored
49 // properties can be used. This routine is seldom called directly; instead it is
50 // used to implement fst.Properties(mask, /*test=*/true).
51 template <class Arc>
52 uint64_t ComputeProperties(const Fst<Arc> &fst, uint64_t mask,
53  uint64_t *known) {
54  using Label = typename Arc::Label;
55  using StateId = typename Arc::StateId;
56  using Weight = typename Arc::Weight;
57  const auto fst_props = fst.Properties(kFstProperties, false); // FST-stored.
58  // Computes (trinary) properties explicitly.
59  // Initialize with binary properties (already known).
60  uint64_t comp_props = fst_props & kBinaryProperties;
61  // Computes these trinary properties with a DFS. We compute only those that
62  // need a DFS here, since we otherwise would like to avoid a DFS since its
63  // stack could grow large.
64  constexpr uint64_t kDfsProps =
67  std::vector<StateId> scc;
68  if (mask & (kDfsProps | kWeightedCycles | kUnweightedCycles)) {
69  SccVisitor<Arc> scc_visitor(&scc, nullptr, nullptr, &comp_props);
70  DfsVisit(fst, &scc_visitor);
71  }
72  // Computes any remaining trinary properties via a state and arcs iterations
73  if (mask & ~(kBinaryProperties | kDfsProps)) {
74  comp_props |= kAcceptor | kNoEpsilons | kNoIEpsilons | kNoOEpsilons |
76  kString;
77  if (mask & (kIDeterministic | kNonIDeterministic)) {
78  comp_props |= kIDeterministic;
79  }
80  if (mask & (kODeterministic | kNonODeterministic)) {
81  comp_props |= kODeterministic;
82  }
83  if (mask & (kDfsProps | kWeightedCycles | kUnweightedCycles)) {
84  comp_props |= kUnweightedCycles;
85  }
86  std::optional<std::unordered_set<Label>> ilabels;
87  std::optional<std::unordered_set<Label>> olabels;
88  StateId nfinal = 0;
89  for (StateIterator<Fst<Arc>> siter(fst); !siter.Done(); siter.Next()) {
90  StateId s = siter.Value();
91  Arc prev_arc;
92  // Creates these only if we need to.
93  if (mask & (kIDeterministic | kNonIDeterministic)) {
94  ilabels.emplace();
95  }
96  if (mask & (kODeterministic | kNonODeterministic)) {
97  olabels.emplace();
98  }
99  bool first_arc = true;
100  for (ArcIterator<Fst<Arc>> aiter(fst, s); !aiter.Done(); aiter.Next()) {
101  const auto &arc = aiter.Value();
102  if (ilabels && ilabels->find(arc.ilabel) != ilabels->end()) {
103  comp_props |= kNonIDeterministic;
104  comp_props &= ~kIDeterministic;
105  }
106  if (olabels && olabels->find(arc.olabel) != olabels->end()) {
107  comp_props |= kNonODeterministic;
108  comp_props &= ~kODeterministic;
109  }
110  if (arc.ilabel != arc.olabel) {
111  comp_props |= kNotAcceptor;
112  comp_props &= ~kAcceptor;
113  }
114  if (arc.ilabel == 0 && arc.olabel == 0) {
115  comp_props |= kEpsilons;
116  comp_props &= ~kNoEpsilons;
117  }
118  if (arc.ilabel == 0) {
119  comp_props |= kIEpsilons;
120  comp_props &= ~kNoIEpsilons;
121  }
122  if (arc.olabel == 0) {
123  comp_props |= kOEpsilons;
124  comp_props &= ~kNoOEpsilons;
125  }
126  if (!first_arc) {
127  if (arc.ilabel < prev_arc.ilabel) {
128  comp_props |= kNotILabelSorted;
129  comp_props &= ~kILabelSorted;
130  }
131  if (arc.olabel < prev_arc.olabel) {
132  comp_props |= kNotOLabelSorted;
133  comp_props &= ~kOLabelSorted;
134  }
135  }
136  if (arc.weight != Weight::One() && arc.weight != Weight::Zero()) {
137  comp_props |= kWeighted;
138  comp_props &= ~kUnweighted;
139  if ((comp_props & kUnweightedCycles) &&
140  scc[s] == scc[arc.nextstate]) {
141  comp_props |= kWeightedCycles;
142  comp_props &= ~kUnweightedCycles;
143  }
144  }
145  if (arc.nextstate <= s) {
146  comp_props |= kNotTopSorted;
147  comp_props &= ~kTopSorted;
148  }
149  if (arc.nextstate != s + 1) {
150  comp_props |= kNotString;
151  comp_props &= ~kString;
152  }
153  prev_arc = arc;
154  first_arc = false;
155  if (ilabels) ilabels->insert(arc.ilabel);
156  if (olabels) olabels->insert(arc.olabel);
157  }
158 
159  if (nfinal > 0) { // Final state not last.
160  comp_props |= kNotString;
161  comp_props &= ~kString;
162  }
163  const auto final_weight = fst.Final(s);
164  if (final_weight != Weight::Zero()) { // Final state.
165  if (final_weight != Weight::One()) {
166  comp_props |= kWeighted;
167  comp_props &= ~kUnweighted;
168  }
169  ++nfinal;
170  } else { // Non-final state.
171  if (fst.NumArcs(s) != 1) {
172  comp_props |= kNotString;
173  comp_props &= ~kString;
174  }
175  }
176  }
177  if (fst.Start() != kNoStateId && fst.Start() != 0) {
178  comp_props |= kNotString;
179  comp_props &= ~kString;
180  }
181  }
182  if (known) *known = KnownProperties(comp_props);
183  return comp_props;
184 }
185 
186 // Similar to ComputeProperties, but uses the properties already stored
187 // in the FST when possible.
188 template <class Arc>
189 uint64_t ComputeOrUseStoredProperties(const Fst<Arc> &fst, uint64_t mask,
190  uint64_t *known) {
191  // Check stored FST properties first.
192  const auto fst_props = fst.Properties(kFstProperties, /*test=*/false);
193  const auto known_props = KnownProperties(fst_props);
194  // If FST contains required info, return it.
195  if ((known_props & mask) == mask) {
196  if (known) *known = known_props;
197  return fst_props;
198  }
199 
200  return ComputeProperties(fst, mask, known);
201 }
202 
203 // This is a wrapper around ComputeProperties that will cause a fatal error if
204 // the stored properties and the computed properties are incompatible when
205 // FST_FLAGS_fst_verify_properties is true. This routine is seldom called directly;
206 // instead it is used to implement fst.Properties(mask, /*test=*/true).
207 template <class Arc>
208 uint64_t TestProperties(const Fst<Arc> &fst, uint64_t mask, uint64_t *known) {
209  if (FST_FLAGS_fst_verify_properties) {
210  const auto stored_props = fst.Properties(kFstProperties, false);
211  const auto computed_props = ComputeProperties(fst, mask, known);
212  if (!CompatProperties(stored_props, computed_props)) {
213  FSTERROR() << "TestProperties: stored FST properties incorrect"
214  << " (stored: props1, computed: props2)";
215  }
216  return computed_props;
217  } else {
218  return ComputeOrUseStoredProperties(fst, mask, known);
219  }
220 }
221 
222 // If all the properties of 'fst' corresponding to 'check_mask' are known,
223 // returns the stored properties. Otherwise, the properties corresponding to
224 // both 'check_mask' and 'test_mask' are computed. This is used to check for
225 // newly-added properties that might not be set in old binary files.
226 template <class Arc>
227 uint64_t CheckProperties(const Fst<Arc> &fst, uint64_t check_mask,
228  uint64_t test_mask) {
229  auto props = fst.Properties(kFstProperties, false);
230  if (FST_FLAGS_fst_verify_properties) {
231  props = TestProperties(fst, check_mask | test_mask, /*known=*/nullptr);
232  } else if ((KnownProperties(props) & check_mask) != check_mask) {
233  props = ComputeProperties(fst, check_mask | test_mask, /*known=*/nullptr);
234  }
235  return props & (check_mask | test_mask);
236 }
237 
238 } // namespace internal
239 } // namespace fst
240 
241 #endif // FST_TEST_PROPERTIES_H_
constexpr uint64_t kCyclic
Definition: properties.h:109
constexpr uint64_t kNotString
Definition: properties.h:139
uint64_t TestProperties(const Fst< Arc > &fst, uint64_t mask, uint64_t *known)
uint64_t ComputeProperties(const Fst< Arc > &fst, uint64_t mask, uint64_t *known)
constexpr uint64_t kWeightedCycles
Definition: properties.h:142
virtual uint64_t Properties(uint64_t mask, bool test) const =0
constexpr uint64_t kOEpsilons
Definition: properties.h:89
constexpr uint64_t kInitialCyclic
Definition: properties.h:114
virtual size_t NumArcs(StateId) const =0
constexpr uint64_t kCoAccessible
Definition: properties.h:129
bool CompatProperties(uint64_t props1, uint64_t props2)
Definition: properties.h:507
constexpr uint64_t kBinaryProperties
Definition: properties.h:310
constexpr uint64_t kNotAccessible
Definition: properties.h:126
constexpr uint64_t kNotTopSorted
Definition: properties.h:121
void DfsVisit(const FST &fst, Visitor *visitor, ArcFilter filter, bool access_only=false)
Definition: dfs-visit.h:112
constexpr uint64_t kInitialAcyclic
Definition: properties.h:116
virtual Weight Final(StateId) const =0
constexpr uint64_t kUnweightedCycles
Definition: properties.h:145
constexpr uint64_t kEpsilons
Definition: properties.h:79
constexpr uint64_t kNotOLabelSorted
Definition: properties.h:101
constexpr uint64_t kTopSorted
Definition: properties.h:119
DECLARE_bool(fst_verify_properties)
constexpr uint64_t kODeterministic
Definition: properties.h:74
constexpr int kNoStateId
Definition: fst.h:196
#define FSTERROR()
Definition: util.h:56
constexpr uint64_t kNonIDeterministic
Definition: properties.h:71
constexpr uint64_t kNotILabelSorted
Definition: properties.h:96
constexpr uint64_t kNoOEpsilons
Definition: properties.h:91
constexpr uint64_t kOLabelSorted
Definition: properties.h:99
constexpr uint64_t kNotAcceptor
Definition: properties.h:66
constexpr uint64_t kAcyclic
Definition: properties.h:111
constexpr uint64_t kNoEpsilons
Definition: properties.h:81
uint64_t CheckProperties(const Fst< Arc > &fst, uint64_t check_mask, uint64_t test_mask)
uint64_t KnownProperties(uint64_t props)
Definition: properties.h:500
constexpr uint64_t kAccessible
Definition: properties.h:124
virtual StateId Start() const =0
constexpr uint64_t kIDeterministic
Definition: properties.h:69
constexpr uint64_t kIEpsilons
Definition: properties.h:84
uint64_t ComputeOrUseStoredProperties(const Fst< Arc > &fst, uint64_t mask, uint64_t *known)
constexpr uint64_t kILabelSorted
Definition: properties.h:94
constexpr uint64_t kFstProperties
Definition: properties.h:326
constexpr uint64_t kUnweighted
Definition: properties.h:106
constexpr uint64_t kNonODeterministic
Definition: properties.h:76
constexpr uint64_t kString
Definition: properties.h:136
constexpr uint64_t kNotCoAccessible
Definition: properties.h:131
constexpr uint64_t kWeighted
Definition: properties.h:104
constexpr uint64_t kNoIEpsilons
Definition: properties.h:86
constexpr uint64_t kAcceptor
Definition: properties.h:64