FST  openfst-1.8.4
OpenFst Library
weight_test.cc
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 // Regression test for FST weights.
19 
20 #include <fst/weight.h>
21 
22 #include <cstddef>
23 #include <cstdint>
24 #include <string>
25 #include <utility>
26 
27 #include <fst/flags.h>
28 #include <fst/expectation-weight.h>
29 #include <fst/float-weight.h>
31 #include <fst/pair-weight.h>
32 #include <fst/power-weight.h>
33 #include <fst/product-weight.h>
34 #include <fst/set-weight.h>
35 #include <fst/signed-log-weight.h>
37 #include <fst/string-weight.h>
38 #include <fst/union-weight.h>
39 #include <fst/test/weight-tester.h>
40 
41 DEFINE_uint64(seed, 403, "random seed");
42 DEFINE_int32(repeat, 10000, "number of test repetitions");
43 
44 namespace {
45 
46 using fst::Adder;
48 using fst::GALLIC;
49 using fst::GallicWeight;
51 using fst::LogWeight;
52 using fst::LogWeightTpl;
53 using fst::MinMaxWeight;
55 using fst::NaturalLess;
56 using fst::PowerWeight;
57 using fst::ProductWeight;
58 using fst::RealWeight;
59 using fst::RealWeightTpl;
60 using fst::SET_BOOLEAN;
63 using fst::SetWeight;
67 using fst::STRING_RIGHT;
68 using fst::StringWeight;
71 using fst::UnionWeight;
72 using fst::WeightConvert;
74 using fst::WeightTester;
75 
76 template <class T>
77 void TestTemplatedWeights(uint64_t seed, int repeat) {
78  WeightGenerate<TropicalWeightTpl<T>> tropical_generate(seed);
79  WeightTester<TropicalWeightTpl<T>> tropical_tester(tropical_generate);
80  tropical_tester.Test(repeat);
81 
82  WeightGenerate<LogWeightTpl<T>> log_generate(seed);
83  WeightTester<LogWeightTpl<T>> log_tester(log_generate);
84  log_tester.Test(repeat);
85 
86  WeightGenerate<RealWeightTpl<T>> real_generate(seed);
87  WeightTester<RealWeightTpl<T>> real_tester(real_generate);
88  real_tester.Test(repeat);
89 
90  WeightGenerate<MinMaxWeightTpl<T>> minmax_generate(seed, true);
91  WeightTester<MinMaxWeightTpl<T>> minmax_tester(minmax_generate);
92  minmax_tester.Test(repeat);
93 
94  WeightGenerate<SignedLogWeightTpl<T>> signedlog_generate(seed, true);
95  WeightTester<SignedLogWeightTpl<T>> signedlog_tester(signedlog_generate);
96  signedlog_tester.Test(repeat);
97 }
98 
99 template <class Weight>
100 void TestAdder(int n) {
101  Weight sum = Weight::Zero();
102  Adder<Weight> adder;
103  for (int i = 0; i < n; ++i) {
104  sum = Plus(sum, Weight::One());
105  adder.Add(Weight::One());
106  }
107  CHECK(ApproxEqual(sum, adder.Sum()));
108 }
109 
110 template <class Weight>
111 void TestSignedAdder(int n) {
112  Weight sum = Weight::Zero();
113  Adder<Weight> adder;
114  const Weight minus_one = Minus(Weight::Zero(), Weight::One());
115  for (int i = 0; i < n; ++i) {
116  if (i < n / 4 || i > 3 * n / 4) {
117  sum = Plus(sum, Weight::One());
118  adder.Add(Weight::One());
119  } else {
120  sum = Minus(sum, Weight::One());
121  adder.Add(minus_one);
122  }
123  }
124  CHECK(ApproxEqual(sum, adder.Sum()));
125 }
126 
127 template <typename Weight1, typename Weight2>
128 void TestWeightConversion(Weight1 w1) {
129  // Tests round-trp conversion.
130  const WeightConvert<Weight2, Weight1> to_w1_;
131  const WeightConvert<Weight1, Weight2> to_w2_;
132  Weight2 w2 = to_w2_(w1);
133  Weight1 nw1 = to_w1_(w2);
134  CHECK_EQ(w1, nw1);
135 }
136 
137 template <typename FromWeight, typename ToWeight>
138 void TestWeightCopy(FromWeight w) {
139  // Test copy constructor.
140  const ToWeight to_copied(w);
141  const FromWeight roundtrip_copied(to_copied);
142  CHECK_EQ(w, roundtrip_copied);
143 
144  // Test copy assign.
145  ToWeight to_copy_assigned;
146  to_copy_assigned = w;
147  CHECK_EQ(to_copied, to_copy_assigned);
148 
149  FromWeight roundtrip_copy_assigned;
150  roundtrip_copy_assigned = to_copy_assigned;
151  CHECK_EQ(w, roundtrip_copy_assigned);
152 }
153 
154 template <typename FromWeight, typename ToWeight>
155 void TestWeightMove(FromWeight w) {
156  // Assume FromWeight -> FromWeight copy works.
157  const FromWeight orig(w);
158  ToWeight to_moved(std::move(w));
159  const FromWeight roundtrip_moved(std::move(to_moved));
160  CHECK_EQ(orig, roundtrip_moved);
161 
162  // Test move assign.
163  w = orig;
164  ToWeight to_move_assigned;
165  to_move_assigned = std::move(w);
166  FromWeight roundtrip_move_assigned;
167  roundtrip_move_assigned = std::move(to_move_assigned);
168  CHECK_EQ(orig, roundtrip_move_assigned);
169 }
170 
171 template <class Weight>
172 void TestImplicitConversion() {
173  // Only test a few of the operations; assumes they are implemented with the
174  // same pattern.
175  CHECK(Weight(2.0f) == 2.0f);
176  CHECK(Weight(2.0) == 2.0);
177  CHECK(2.0f == Weight(2.0f));
178  CHECK(2.0 == Weight(2.0));
179 
180  CHECK_EQ(Weight::Zero(), Times(Weight::Zero(), 3.0f));
181  CHECK_EQ(Weight::Zero(), Times(Weight::Zero(), 3.0));
182  CHECK_EQ(Weight::Zero(), Times(3.0, Weight::Zero()));
183 
184  CHECK_EQ(Weight(3.0), Plus(Weight::Zero(), 3.0f));
185  CHECK_EQ(Weight(3.0), Plus(Weight::Zero(), 3.0));
186  CHECK_EQ(Weight(3.0), Plus(3.0, Weight::Zero()));
187 }
188 
189 void TestPowerWeightGetSetValue() {
190  PowerWeight<LogWeight, 3> w;
191  // LogWeight has unspecified initial value, so don't check it.
192  w.SetValue(0, LogWeight(2));
193  w.SetValue(1, LogWeight(3));
194  CHECK_EQ(LogWeight(2), w.Value(0));
195  CHECK_EQ(LogWeight(3), w.Value(1));
196 }
197 
198 void TestSparsePowerWeightGetSetValue() {
199  const LogWeight default_value(17);
200  SparsePowerWeight<LogWeight> w;
201  w.SetDefaultValue(default_value);
202 
203  // All gets should be the default.
204  CHECK_EQ(default_value, w.Value(0));
205  CHECK_EQ(default_value, w.Value(100));
206 
207  // First set should fill first_.
208  w.SetValue(10, LogWeight(10));
209  CHECK_EQ(LogWeight(10), w.Value(10));
210  w.SetValue(10, LogWeight(20));
211  CHECK_EQ(LogWeight(20), w.Value(10));
212 
213  // Add a smaller index.
214  w.SetValue(5, LogWeight(5));
215  CHECK_EQ(LogWeight(5), w.Value(5));
216  CHECK_EQ(LogWeight(20), w.Value(10));
217 
218  // Add some larger indices.
219  w.SetValue(30, LogWeight(30));
220  CHECK_EQ(LogWeight(5), w.Value(5));
221  CHECK_EQ(LogWeight(20), w.Value(10));
222  CHECK_EQ(LogWeight(30), w.Value(30));
223 
224  w.SetValue(29, LogWeight(29));
225  CHECK_EQ(LogWeight(5), w.Value(5));
226  CHECK_EQ(LogWeight(20), w.Value(10));
227  CHECK_EQ(LogWeight(29), w.Value(29));
228  CHECK_EQ(LogWeight(30), w.Value(30));
229 
230  w.SetValue(31, LogWeight(31));
231  CHECK_EQ(LogWeight(5), w.Value(5));
232  CHECK_EQ(LogWeight(20), w.Value(10));
233  CHECK_EQ(LogWeight(29), w.Value(29));
234  CHECK_EQ(LogWeight(30), w.Value(30));
235  CHECK_EQ(LogWeight(31), w.Value(31));
236 
237  // Replace a value.
238  w.SetValue(30, LogWeight(60));
239  CHECK_EQ(LogWeight(60), w.Value(30));
240 
241  // Replace a value with the default.
242  CHECK_EQ(5, w.Size());
243  w.SetValue(30, default_value);
244  CHECK_EQ(default_value, w.Value(30));
245  CHECK_EQ(4, w.Size());
246 
247  // Replace lowest index by the default value.
248  w.SetValue(5, default_value);
249  CHECK_EQ(default_value, w.Value(5));
250  CHECK_EQ(3, w.Size());
251 
252  // Clear out everything.
253  w.SetValue(31, default_value);
254  w.SetValue(29, default_value);
255  w.SetValue(10, default_value);
256  CHECK_EQ(0, w.Size());
257 
258  CHECK_EQ(default_value, w.Value(5));
259  CHECK_EQ(default_value, w.Value(10));
260  CHECK_EQ(default_value, w.Value(29));
261  CHECK_EQ(default_value, w.Value(30));
262  CHECK_EQ(default_value, w.Value(31));
263 }
264 
265 // If this test fails, it is possible that x == x will not
266 // hold for FloatWeight, breaking NaturalLess and probably more.
267 // To trigger these failures, use g++ -O -m32 -mno-sse.
268 template <class T>
269 bool FloatEqualityIsReflexive(T m) {
270  // The idea here is that x is spilled to memory, but
271  // y remains in an 80-bit register with extra precision,
272  // causing it to compare unequal to x.
273  volatile T x = 1.111;
274  x *= m;
275 
276  T y = 1.111;
277  y *= m;
278 
279  return x == y;
280 }
281 
282 void TestFloatEqualityIsReflexive() {
283  // Use a volatile test_value to avoid excessive inlining / optimization
284  // breaking what we're trying to test.
285  volatile double test_value = 1.1;
286  CHECK(FloatEqualityIsReflexive(static_cast<float>(test_value)));
287  CHECK(FloatEqualityIsReflexive(test_value));
288 }
289 
290 } // namespace
291 
292 int main(int argc, char **argv) {
293  SET_FLAGS(argv[0], &argc, &argv, true);
294 
295  TestTemplatedWeights<float>(FST_FLAGS_seed,
296  FST_FLAGS_repeat);
297  TestTemplatedWeights<double>(FST_FLAGS_seed,
298  FST_FLAGS_repeat);
299  SetFlag(&FST_FLAGS_fst_weight_parentheses, "()");
300  TestTemplatedWeights<float>(FST_FLAGS_seed,
301  FST_FLAGS_repeat);
302  TestTemplatedWeights<double>(FST_FLAGS_seed,
303  FST_FLAGS_repeat);
304  SetFlag(&FST_FLAGS_fst_weight_parentheses, "");
305 
306  // Makes sure type names for templated weights are consistent.
307  CHECK_EQ(TropicalWeight::Type(), "tropical");
308  CHECK(TropicalWeightTpl<double>::Type() != TropicalWeightTpl<float>::Type());
309  CHECK_EQ(LogWeight::Type(), "log");
310  CHECK(LogWeightTpl<double>::Type() != LogWeightTpl<float>::Type());
311  CHECK_EQ(RealWeight::Type(), "real");
312  CHECK(RealWeightTpl<double>::Type() != RealWeightTpl<float>::Type());
313  TropicalWeightTpl<double> w(2.0);
314  TropicalWeight tw(2.0);
315  CHECK_EQ(w.Value(), tw.Value());
316 
317  TestAdder<TropicalWeight>(1000);
318  TestAdder<LogWeight>(1000);
319  TestAdder<RealWeight>(1000);
320  TestSignedAdder<SignedLogWeight>(1000);
321 
322  TestImplicitConversion<TropicalWeight>();
323  TestImplicitConversion<LogWeight>();
324  TestImplicitConversion<RealWeight>();
325  TestImplicitConversion<MinMaxWeight>();
326 
327  TestWeightConversion<TropicalWeight, LogWeight>(2.0);
328 
329  using LeftStringWeight = StringWeight<int>;
330  WeightGenerate<LeftStringWeight> left_string_generate(
331  FST_FLAGS_seed);
332  WeightTester<LeftStringWeight> left_string_tester(left_string_generate);
333  left_string_tester.Test(FST_FLAGS_repeat);
334 
335  using RightStringWeight = StringWeight<int, STRING_RIGHT>;
336  WeightGenerate<RightStringWeight> right_string_generate(
337  FST_FLAGS_seed);
338  WeightTester<RightStringWeight> right_string_tester(right_string_generate);
339  right_string_tester.Test(FST_FLAGS_repeat);
340 
341  // STRING_RESTRICT not tested since it requires equal strings,
342  // so would fail.
343 
344  using IUSetWeight = SetWeight<int, SET_INTERSECT_UNION>;
345  WeightGenerate<IUSetWeight> iu_set_generate(FST_FLAGS_seed);
346  WeightTester<IUSetWeight> iu_set_tester(iu_set_generate);
347  iu_set_tester.Test(FST_FLAGS_repeat);
348 
349  using UISetWeight = SetWeight<int, SET_UNION_INTERSECT>;
350  WeightGenerate<UISetWeight> ui_set_generate(FST_FLAGS_seed);
351  WeightTester<UISetWeight> ui_set_tester(ui_set_generate);
352  ui_set_tester.Test(FST_FLAGS_repeat);
353 
354  // SET_INTERSECT_UNION_RESTRICT not tested since it requires equal sets,
355  // so would fail.
356 
357  using BoolSetWeight = SetWeight<int, SET_BOOLEAN>;
358  WeightGenerate<BoolSetWeight> bool_set_generate(FST_FLAGS_seed);
359  WeightTester<BoolSetWeight> bool_set_tester(bool_set_generate);
360  bool_set_tester.Test(FST_FLAGS_repeat);
361 
362  TestWeightConversion<IUSetWeight, UISetWeight>(iu_set_generate());
363 
364  TestWeightCopy<IUSetWeight, UISetWeight>(iu_set_generate());
365  TestWeightCopy<IUSetWeight, BoolSetWeight>(iu_set_generate());
366  TestWeightCopy<UISetWeight, IUSetWeight>(ui_set_generate());
367  TestWeightCopy<UISetWeight, BoolSetWeight>(ui_set_generate());
368  TestWeightCopy<BoolSetWeight, IUSetWeight>(bool_set_generate());
369  TestWeightCopy<BoolSetWeight, UISetWeight>(bool_set_generate());
370 
371  TestWeightMove<IUSetWeight, UISetWeight>(iu_set_generate());
372  TestWeightMove<IUSetWeight, BoolSetWeight>(iu_set_generate());
373  TestWeightMove<UISetWeight, IUSetWeight>(ui_set_generate());
374  TestWeightMove<UISetWeight, BoolSetWeight>(ui_set_generate());
375  TestWeightMove<BoolSetWeight, IUSetWeight>(bool_set_generate());
376  TestWeightMove<BoolSetWeight, UISetWeight>(bool_set_generate());
377 
378  // COMPOSITE WEIGHTS AND TESTERS - DEFINITIONS
379 
380  using TropicalGallicWeight = GallicWeight<int, TropicalWeight>;
381  WeightGenerate<TropicalGallicWeight> tropical_gallic_generate(
382  FST_FLAGS_seed, true);
383  WeightTester<TropicalGallicWeight> tropical_gallic_tester(
384  tropical_gallic_generate);
385 
386  using TropicalGenGallicWeight = GallicWeight<int, TropicalWeight, GALLIC>;
387  WeightGenerate<TropicalGenGallicWeight> tropical_gen_gallic_generate(
388  FST_FLAGS_seed, false);
389  WeightTester<TropicalGenGallicWeight> tropical_gen_gallic_tester(
390  tropical_gen_gallic_generate);
391 
392  using TropicalProductWeight = ProductWeight<TropicalWeight, TropicalWeight>;
393  WeightGenerate<TropicalProductWeight> tropical_product_generate(
394  FST_FLAGS_seed);
395  WeightTester<TropicalProductWeight> tropical_product_tester(
396  tropical_product_generate);
397 
398  using TropicalLexicographicWeight =
399  LexicographicWeight<TropicalWeight, TropicalWeight>;
400  WeightGenerate<TropicalLexicographicWeight> tropical_lexicographic_generate(
401  FST_FLAGS_seed);
402  WeightTester<TropicalLexicographicWeight> tropical_lexicographic_tester(
403  tropical_lexicographic_generate);
404 
405  using TropicalCubeWeight = PowerWeight<TropicalWeight, 3>;
406  WeightGenerate<TropicalCubeWeight> tropical_cube_generate(
407  FST_FLAGS_seed);
408  WeightTester<TropicalCubeWeight> tropical_cube_tester(tropical_cube_generate);
409 
410  using FirstNestedProductWeight =
411  ProductWeight<TropicalProductWeight, TropicalWeight>;
412  WeightGenerate<FirstNestedProductWeight> first_nested_product_generate(
413  FST_FLAGS_seed);
414  WeightTester<FirstNestedProductWeight> first_nested_product_tester(
415  first_nested_product_generate);
416 
417  using SecondNestedProductWeight =
418  ProductWeight<TropicalWeight, TropicalProductWeight>;
419  WeightGenerate<SecondNestedProductWeight> second_nested_product_generate(
420  FST_FLAGS_seed);
421  WeightTester<SecondNestedProductWeight> second_nested_product_tester(
422  second_nested_product_generate);
423 
424  using NestedProductCubeWeight = PowerWeight<FirstNestedProductWeight, 3>;
425  WeightGenerate<NestedProductCubeWeight> nested_product_cube_generate(
426  FST_FLAGS_seed);
427  WeightTester<NestedProductCubeWeight> nested_product_cube_tester(
428  nested_product_cube_generate);
429 
430  using SparseNestedProductCubeWeight =
431  SparsePowerWeight<NestedProductCubeWeight, size_t>;
432  WeightGenerate<SparseNestedProductCubeWeight>
433  sparse_nested_product_cube_generate(FST_FLAGS_seed);
434  WeightTester<SparseNestedProductCubeWeight> sparse_nested_product_cube_tester(
435  sparse_nested_product_cube_generate);
436 
437  using LogSparsePowerWeight = SparsePowerWeight<LogWeight, size_t>;
438  WeightGenerate<LogSparsePowerWeight> log_sparse_power_generate(
439  FST_FLAGS_seed);
440  WeightTester<LogSparsePowerWeight> log_sparse_power_tester(
441  log_sparse_power_generate);
442 
443  using LogLogExpectationWeight = ExpectationWeight<LogWeight, LogWeight>;
444  WeightGenerate<LogLogExpectationWeight> log_log_expectation_generate(
445  FST_FLAGS_seed);
446  WeightTester<LogLogExpectationWeight> log_log_expectation_tester(
447  log_log_expectation_generate);
448 
449  using RealRealExpectationWeight = ExpectationWeight<RealWeight, RealWeight>;
450  WeightGenerate<RealRealExpectationWeight> real_real_expectation_generate(
451  FST_FLAGS_seed);
452  WeightTester<RealRealExpectationWeight> real_real_expectation_tester(
453  real_real_expectation_generate);
454 
455  using LogLogSparseExpectationWeight =
456  ExpectationWeight<LogWeight, LogSparsePowerWeight>;
457  WeightGenerate<LogLogSparseExpectationWeight>
458  log_log_sparse_expectation_generate(FST_FLAGS_seed);
459  WeightTester<LogLogSparseExpectationWeight> log_log_sparse_expectation_tester(
460  log_log_sparse_expectation_generate);
461 
462  struct UnionWeightOptions {
463  using Compare = NaturalLess<TropicalWeight>;
464 
465  struct Merge {
466  TropicalWeight operator()(const TropicalWeight &w1,
467  const TropicalWeight &w2) const {
468  return w1;
469  }
470  };
471 
472  using ReverseOptions = UnionWeightOptions;
473  };
474 
475  using TropicalUnionWeight = UnionWeight<TropicalWeight, UnionWeightOptions>;
476  WeightGenerate<TropicalUnionWeight> tropical_union_generate(
477  FST_FLAGS_seed);
478  WeightTester<TropicalUnionWeight> tropical_union_tester(
479  tropical_union_generate);
480 
481  // COMPOSITE WEIGHTS AND TESTERS - TESTING
482 
483  // Tests composite weight I/O with parentheses.
484  SetFlag(&FST_FLAGS_fst_weight_parentheses, "()");
485 
486  // Unnested composite.
487  tropical_gallic_tester.Test(FST_FLAGS_repeat);
488  tropical_gen_gallic_tester.Test(FST_FLAGS_repeat);
489  tropical_product_tester.Test(FST_FLAGS_repeat);
490  tropical_lexicographic_tester.Test(FST_FLAGS_repeat);
491  tropical_cube_tester.Test(FST_FLAGS_repeat);
492  log_sparse_power_tester.Test(FST_FLAGS_repeat);
493  log_log_expectation_tester.Test(FST_FLAGS_repeat);
494  real_real_expectation_tester.Test(FST_FLAGS_repeat);
495  tropical_union_tester.Test(FST_FLAGS_repeat);
496 
497  // Nested composite.
498  first_nested_product_tester.Test(FST_FLAGS_repeat);
499  second_nested_product_tester.Test(5);
500  nested_product_cube_tester.Test(FST_FLAGS_repeat);
501  sparse_nested_product_cube_tester.Test(FST_FLAGS_repeat);
502  log_log_sparse_expectation_tester.Test(FST_FLAGS_repeat);
503 
504  // ... and tests composite weight I/O without parentheses.
505  SetFlag(&FST_FLAGS_fst_weight_parentheses, "");
506 
507  // Unnested composite.
508  tropical_gallic_tester.Test(FST_FLAGS_repeat);
509  tropical_product_tester.Test(FST_FLAGS_repeat);
510  tropical_lexicographic_tester.Test(FST_FLAGS_repeat);
511  tropical_cube_tester.Test(FST_FLAGS_repeat);
512  log_sparse_power_tester.Test(FST_FLAGS_repeat);
513  log_log_expectation_tester.Test(FST_FLAGS_repeat);
514  tropical_union_tester.Test(FST_FLAGS_repeat);
515 
516  // Nested composite.
517  second_nested_product_tester.Test(FST_FLAGS_repeat);
518  log_log_sparse_expectation_tester.Test(FST_FLAGS_repeat);
519 
520  TestPowerWeightGetSetValue();
521  TestSparsePowerWeightGetSetValue();
522 
523  TestFloatEqualityIsReflexive();
524 
525  return 0;
526 }
RealWeightTpl< float > RealWeight
Definition: float-weight.h:710
ErrorWeight Plus(const ErrorWeight &, const ErrorWeight &)
Definition: error-weight.h:61
DEFINE_int32(repeat, 10000,"number of test repetitions")
ErrorWeight Times(const ErrorWeight &, const ErrorWeight &)
Definition: error-weight.h:64
int main(int argc, char **argv)
Definition: weight_test.cc:292
#define SET_FLAGS(usage, argc, argv, rmflags)
Definition: flags.h:226
LogWeightTpl< float > LogWeight
Definition: float-weight.h:468
TropicalWeightTpl< float > TropicalWeight
Definition: float-weight.h:267
MinMaxWeightTpl< float > MinMaxWeight
Definition: float-weight.h:909
#define CHECK_EQ(x, y)
Definition: log.h:66
LogWeightTpl< T > Minus(const LogWeightTpl< T > &w1, const LogWeightTpl< T > &w2)
Definition: float-weight.h:542
DEFINE_uint64(seed, 403,"random seed")
void SetFlag(Type *flag, Value value)
Definition: flags.h:220
#define CHECK(x)
Definition: log.h:65
SignedLogWeightTpl< float > SignedLogWeight
bool ApproxEqual(const ErrorWeight &, const ErrorWeight &, float)
Definition: error-weight.h:58