// float-weight.h
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright 2005-2010 Google, Inc.
// Author: riley@google.com (Michael Riley)
//
// \file
// Float weight set and associated semiring operation definitions.
//
#ifndef FST_LIB_FLOAT_WEIGHT_H__
#define FST_LIB_FLOAT_WEIGHT_H__
#include <limits>
#include <climits>
#include <sstream>
#include <string>
#include <fst/util.h>
#include <fst/weight.h>
namespace fst {
// numeric limits class
template <class T>
class FloatLimits {
public:
static const T PosInfinity() {
static const T pos_infinity = numeric_limits<T>::infinity();
return pos_infinity;
}
static const T NegInfinity() {
static const T neg_infinity = -PosInfinity();
return neg_infinity;
}
static const T NumberBad() {
static const T number_bad = numeric_limits<T>::quiet_NaN();
return number_bad;
}
};
// weight class to be templated on floating-points types
template <class T = float>
class FloatWeightTpl {
public:
FloatWeightTpl() {}
FloatWeightTpl(T f) : value_(f) {}
FloatWeightTpl(const FloatWeightTpl<T> &w) : value_(w.value_) {}
FloatWeightTpl<T> &operator=(const FloatWeightTpl<T> &w) {
value_ = w.value_;
return *this;
}
istream &Read(istream &strm) {
return ReadType(strm, &value_);
}
ostream &Write(ostream &strm) const {
return WriteType(strm, value_);
}
size_t Hash() const {
union {
T f;
size_t s;
} u;
u.s = 0;
u.f = value_;
return u.s;
}
const T &Value() const { return value_; }
protected:
void SetValue(const T &f) { value_ = f; }
inline static string GetPrecisionString() {
int64 size = sizeof(T);
if (size == sizeof(float)) return "";
size *= CHAR_BIT;
string result;
Int64ToStr(size, &result);
return result;
}
private:
T value_;
};
// Single-precision float weight
typedef FloatWeightTpl<float> FloatWeight;
template <class T>
inline bool operator==(const FloatWeightTpl<T> &w1,
const FloatWeightTpl<T> &w2) {
// Volatile qualifier thwarts over-aggressive compiler optimizations
// that lead to problems esp. with NaturalLess().
volatile T v1 = w1.Value();
volatile T v2 = w2.Value();
return v1 == v2;
}
inline bool operator==(const FloatWeightTpl<double> &w1,
const FloatWeightTpl<double> &w2) {
return operator==<double>(w1, w2);
}
inline bool operator==(const FloatWeightTpl<float> &w1,
const FloatWeightTpl<float> &w2) {
return operator==<float>(w1, w2);
}
template <class T>
inline bool operator!=(const FloatWeightTpl<T> &w1,
const FloatWeightTpl<T> &w2) {
return !(w1 == w2);
}
inline bool operator!=(const FloatWeightTpl<double> &w1,
const FloatWeightTpl<double> &w2) {
return operator!=<double>(w1, w2);
}
inline bool operator!=(const FloatWeightTpl<float> &w1,
const FloatWeightTpl<float> &w2) {
return operator!=<float>(w1, w2);
}
template <class T>
inline bool ApproxEqual(const FloatWeightTpl<T> &w1,
const FloatWeightTpl<T> &w2,
float delta = kDelta) {
return w1.Value() <= w2.Value() + delta && w2.Value() <= w1.Value() + delta;
}
template <class T>
inline ostream &operator<<(ostream &strm, const FloatWeightTpl<T> &w) {
if (w.Value() == FloatLimits<T>::PosInfinity())
return strm << "Infinity";
else if (w.Value() == FloatLimits<T>::NegInfinity())
return strm << "-Infinity";
else if (w.Value() != w.Value()) // Fails for NaN
return strm << "BadNumber";
else
return strm << w.Value();
}
template <class T>
inline istream &operator>>(istream &strm, FloatWeightTpl<T> &w) {
string s;
strm >> s;
if (s == "Infinity") {
w = FloatWeightTpl<T>(FloatLimits<T>::PosInfinity());
} else if (s == "-Infinity") {
w = FloatWeightTpl<T>(FloatLimits<T>::NegInfinity());
} else {
char *p;
T f = strtod(s.c_str(), &p);
if (p < s.c_str() + s.size())
strm.clear(std::ios::badbit);
else
w = FloatWeightTpl<T>(f);
}
return strm;
}
// Tropical semiring: (min, +, inf, 0)
template <class T>
class TropicalWeightTpl : public FloatWeightTpl<T> {
public:
using FloatWeightTpl<T>::Value;
typedef TropicalWeightTpl<T> ReverseWeight;
TropicalWeightTpl() : FloatWeightTpl<T>() {}
TropicalWeightTpl(T f) : FloatWeightTpl<T>(f) {}
TropicalWeightTpl(const TropicalWeightTpl<T> &w) : FloatWeightTpl<T>(w) {}
static const TropicalWeightTpl<T> Zero() {
return TropicalWeightTpl<T>(FloatLimits<T>::PosInfinity()); }
static const TropicalWeightTpl<T>