FST  openfst-1.8.3
OpenFst Library
equal.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 // Function to test equality of two FSTs.
19 
20 #ifndef FST_EQUAL_H_
21 #define FST_EQUAL_H_
22 
23 #include <cstdint>
24 #include <string>
25 
26 #include <fst/log.h>
27 #include <fst/fst.h>
28 #include <fst/properties.h>
29 #include <fst/symbol-table.h>
30 #include <fst/util.h>
31 #include <fst/weight.h>
32 
33 namespace fst {
34 
35 inline constexpr uint8_t kEqualFsts = 0x01;
36 inline constexpr uint8_t kEqualFstTypes = 0x02;
37 inline constexpr uint8_t kEqualCompatProperties = 0x04;
38 inline constexpr uint8_t kEqualCompatSymbols = 0x08;
39 inline constexpr uint8_t kEqualAll =
40  kEqualFsts | kEqualFstTypes | kEqualCompatProperties | kEqualCompatSymbols;
41 
43  public:
44  explicit WeightApproxEqual(float delta) : delta_(delta) {}
45 
46  // We use two weight types to avoid some conflicts caused by
47  // conversions.
48  template <class Weight1, class Weight2>
49  bool operator()(const Weight1 &w1, const Weight2 &w2) const {
50  return ApproxEqual(w1, w2, delta_);
51  }
52 
53  private:
54  const float delta_;
55 };
56 
57 // Tests if two FSTs have the same states and arcs in the same order (when
58 // etype & kEqualFst); optionally, also checks equality of FST types
59 // (etype & kEqualFstTypes) and compatibility of stored properties
60 // (etype & kEqualCompatProperties) and of symbol tables
61 // (etype & kEqualCompatSymbols).
62 template <class Arc, class WeightEqual>
63 bool Equal(const Fst<Arc> &fst1, const Fst<Arc> &fst2, WeightEqual weight_equal,
64  uint8_t etype = kEqualFsts) {
65  if ((etype & kEqualFstTypes) && (fst1.Type() != fst2.Type())) {
66  VLOG(1) << "Equal: Mismatched FST types (" << fst1.Type()
67  << " != " << fst2.Type() << ")";
68  return false;
69  }
70  if ((etype & kEqualCompatProperties) &&
72  fst2.Properties(kCopyProperties, false))) {
73  VLOG(1) << "Equal: Properties not compatible";
74  return false;
75  }
76  if (etype & kEqualCompatSymbols) {
77  if (!CompatSymbols(fst1.InputSymbols(), fst2.InputSymbols(), false)) {
78  VLOG(1) << "Equal: Input symbols not compatible";
79  return false;
80  }
81  if (!CompatSymbols(fst1.OutputSymbols(), fst2.OutputSymbols(), false)) {
82  VLOG(1) << "Equal: Output symbols not compatible";
83  return false;
84  }
85  }
86  if (!(etype & kEqualFsts)) return true;
87  if (fst1.Start() != fst2.Start()) {
88  VLOG(1) << "Equal: Mismatched start states (" << fst1.Start()
89  << " != " << fst2.Start() << ")";
90  return false;
91  }
92  StateIterator<Fst<Arc>> siter1(fst1);
93  StateIterator<Fst<Arc>> siter2(fst2);
94  while (!siter1.Done() || !siter2.Done()) {
95  if (siter1.Done() || siter2.Done()) {
96  VLOG(1) << "Equal: Mismatched number of states";
97  return false;
98  }
99  const auto s1 = siter1.Value();
100  const auto s2 = siter2.Value();
101  if (s1 != s2) {
102  VLOG(1) << "Equal: Mismatched states (" << s1 << "!= " << s2 << ")";
103  return false;
104  }
105  const auto &final1 = fst1.Final(s1);
106  const auto &final2 = fst2.Final(s2);
107  if (!weight_equal(final1, final2)) {
108  VLOG(1) << "Equal: Mismatched final weights at state " << s1 << " ("
109  << final1 << " != " << final2 << ")";
110  return false;
111  }
112  ArcIterator<Fst<Arc>> aiter1(fst1, s1);
113  ArcIterator<Fst<Arc>> aiter2(fst2, s2);
114  for (auto a = 0; !aiter1.Done() || !aiter2.Done(); ++a) {
115  if (aiter1.Done() || aiter2.Done()) {
116  VLOG(1) << "Equal: Mismatched number of arcs at state " << s1;
117  return false;
118  }
119  const auto &arc1 = aiter1.Value();
120  const auto &arc2 = aiter2.Value();
121  if (arc1.ilabel != arc2.ilabel) {
122  VLOG(1) << "Equal: Mismatched arc input labels at state " << s1
123  << ", arc " << a << " (" << arc1.ilabel << " != " << arc2.ilabel
124  << ")";
125  return false;
126  } else if (arc1.olabel != arc2.olabel) {
127  VLOG(1) << "Equal: Mismatched arc output labels at state " << s1
128  << ", arc " << a << " (" << arc1.olabel << " != " << arc2.olabel
129  << ")";
130  return false;
131  } else if (!weight_equal(arc1.weight, arc2.weight)) {
132  VLOG(1) << "Equal: Mismatched arc weights at state " << s1 << ", arc "
133  << a << " (" << arc1.weight << " != " << arc2.weight << ")";
134  return false;
135  } else if (arc1.nextstate != arc2.nextstate) {
136  VLOG(1) << "Equal: Mismatched next state at state " << s1 << ", arc "
137  << a << " (" << arc1.nextstate << " != " << arc2.nextstate
138  << ")";
139  return false;
140  }
141  aiter1.Next();
142  aiter2.Next();
143  }
144  // Sanity checks: should never fail.
145  if (fst1.NumArcs(s1) != fst2.NumArcs(s2)) {
146  FSTERROR() << "Equal: Inconsistent arc counts at state " << s1 << " ("
147  << fst1.NumArcs(s1) << " != " << fst2.NumArcs(s2) << ")";
148  return false;
149  }
150  if (fst1.NumInputEpsilons(s1) != fst2.NumInputEpsilons(s2)) {
151  FSTERROR() << "Equal: Inconsistent input epsilon counts at state " << s1
152  << " (" << fst1.NumInputEpsilons(s1)
153  << " != " << fst2.NumInputEpsilons(s2) << ")";
154  return false;
155  }
156  if (fst1.NumOutputEpsilons(s1) != fst2.NumOutputEpsilons(s2)) {
157  FSTERROR() << "Equal: Inconsistent output epsilon counts at state " << s1
158  << " (" << fst1.NumOutputEpsilons(s1)
159  << " != " << fst2.NumOutputEpsilons(s2) << ")";
160  }
161  siter1.Next();
162  siter2.Next();
163  }
164  return true;
165 }
166 
167 template <class Arc>
168 bool Equal(const Fst<Arc> &fst1, const Fst<Arc> &fst2, float delta = kDelta,
169  uint8_t etype = kEqualFsts) {
170  return Equal(fst1, fst2, WeightApproxEqual(delta), etype);
171 }
172 
173 // Support double deltas without forcing all clients to cast to float.
174 // Without this overload, Equal<Arc, WeightEqual=double> will be chosen,
175 // since it is a better match than double -> float narrowing, but
176 // the instantiation will fail.
177 template <class Arc>
178 bool Equal(const Fst<Arc> &fst1, const Fst<Arc> &fst2, double delta,
179  uint8_t etype = kEqualFsts) {
180  return Equal(fst1, fst2, WeightApproxEqual(static_cast<float>(delta)), etype);
181 }
182 
183 } // namespace fst
184 
185 #endif // FST_EQUAL_H_
virtual uint64_t Properties(uint64_t mask, bool test) const =0
virtual size_t NumArcs(StateId) const =0
bool CompatProperties(uint64_t props1, uint64_t props2)
Definition: properties.h:507
constexpr uint8_t kEqualCompatProperties
Definition: equal.h:37
virtual Weight Final(StateId) const =0
WeightApproxEqual(float delta)
Definition: equal.h:44
constexpr uint8_t kEqualFstTypes
Definition: equal.h:36
const Arc & Value() const
Definition: fst.h:536
virtual size_t NumInputEpsilons(StateId) const =0
#define FSTERROR()
Definition: util.h:56
virtual const std::string & Type() const =0
constexpr uint8_t kEqualAll
Definition: equal.h:39
constexpr uint64_t kCopyProperties
Definition: properties.h:163
#define VLOG(level)
Definition: log.h:54
virtual StateId Start() const =0
StateId Value() const
Definition: fst.h:419
bool Done() const
Definition: fst.h:532
bool Equal(const Fst< Arc > &fst1, const Fst< Arc > &fst2, WeightEqual weight_equal, uint8_t etype=kEqualFsts)
Definition: equal.h:63
virtual const SymbolTable * InputSymbols() const =0
void Next()
Definition: fst.h:421
bool Done() const
Definition: fst.h:415
bool operator()(const Weight1 &w1, const Weight2 &w2) const
Definition: equal.h:49
bool CompatSymbols(const SymbolTable *syms1, const SymbolTable *syms2, bool warning=true)
constexpr uint8_t kEqualFsts
Definition: equal.h:35
constexpr uint8_t kEqualCompatSymbols
Definition: equal.h:38
virtual size_t NumOutputEpsilons(StateId) const =0
constexpr float kDelta
Definition: weight.h:133
bool ApproxEqual(const ErrorWeight &, const ErrorWeight &, float)
Definition: error-weight.h:58
virtual const SymbolTable * OutputSymbols() const =0
void Next()
Definition: fst.h:540